Sommario
Introduzione ................................................................................................................................................................ 8
Il Computer .............................................................................................................................................................. 3
CPU ...................................................................................................................................................................... 3
PSW...................................................................................................................................................................... 3
MMU.................................................................................................................................................................... 4
Cache ................................................................................................................................................................... 5
Interrupt .................................................................................................................................................................. 5
Ciclo di CPU.......................................................................................................................................................... 7
Processi ........................................................................................................................................................................ 9
PCB ........................................................................................................................................................................... 9
ECB ......................................................................................................................................................................... 11
Multitasking ........................................................................................................................................................... 11
Gestione di un processo........................................................................................................................................ 12
Casi studio.............................................................................................................................................................. 15
Thread ........................................................................................................................................................................ 17
1
Appunti di Sistemi Operativi Teoria
Scheduler ................................................................................................................................................................... 19
Scheduling a lotteria.............................................................................................................................................. 26
Sezione critica.................................................................................................................................................... 29
2
Appunti di Sistemi Operativi Teoria
Deadlock .................................................................................................................................................................... 67
Memoria .................................................................................................................................................................... 70
Swapping ............................................................................................................................................................... 71
Binding ................................................................................................................................................................... 71
Partizionamento ........................................................................................................................................................ 72
Partizionamento variabile................................................................................................................................. 73
Paginazione............................................................................................................................................................ 76
3
Appunti di Sistemi Operativi Teoria
EAT ......................................................................................................................................................................... 83
Riepilogo ................................................................................................................................................................ 91
Segmentazione ...................................................................................................................................................... 91
Segmentazione paginata....................................................................................................................................... 92
Casi studio.............................................................................................................................................................. 93
FileSystem .................................................................................................................................................................. 95
Tipi di file................................................................................................................................................................ 97
4
Appunti di Sistemi Operativi Teoria
Pila ..................................................................................................................................................................... 98
Sequenziale ....................................................................................................................................................... 98
.............................................................................................................................................................................. 107
5
Appunti di Sistemi Operativi Teoria
Look...................................................................................................................................................................... 117
6
Appunti di Sistemi Operativi Teoria
7
Appunti di Sistemi Operativi Teoria
Introduzione
Questi appunti sono nati dall’esigenza di avere un riferimento più completo di appunti che
possono aiutare noi studenti a superare l’esame. Sono una rivisitazione e miglioramento degli
appunti precedenti di Liccardo Giuseppe uniti a quelli delle lezioni in aula e a quelli dei libri.
Sono stati aggiunte le seguenti modifiche:
Miglioramento della spiegazione dell’algoritmo Migliorate le variabili di condizione
Gestione dettagliata dell I/O tramite DMA e Inserimento della Regione critica, prod-cons
Inserimento della struttura del file system con Aggiunto Allocatore Lazy buddy
Inserimento della proprietà di Invarianza dei Aggiunto il produttore consumatore con variabili
semafori di condizione
8
Appunti di Sistemi Operativi Teoria
Il Sistema Operativo
Il Sistema operativo può essere visto come un gestore di risorse. Possiamo avere due tipologie
di strutture di un Sistema operativo:
- Struttura stratificata, la visione stratificata (a cipolla) del Sistema Operativo ci
fornisce un’idea a strati ovvero che nel momento in cui si debba far intervenire
una parte del SO quest’ultimo debba essere attraversato per intero, questo non è
corretto. Vengono coinvolti solo alcuni strati.
Dietro agli strati di cui è composto il Sistena operativo vi sono le strutture dati che
essi utilizzano:
Tabella dei processi (utilizzata dal kernel o nucleo) è formata da un
insieme di record ognuno dei quali suddivisi nei seguenti campi:
o Id del processo
o L’allocazione in memoria (pagine o segmenti assegnati al
processo), cioè contiene il puntatore alla tabella di allocazione
della memoria dove sono contenute queste informazioni
o File utilizzati dal processo, contiene il puntatore alla tabella dei
file aperti
o Il programma eseguito
o Le informazioni di stato
o Le informazioni contabili cioè il modo in cui è stato utilizzato il
processo in funzione al tempo impiegato, allo spazio occupato ecc
Tabella di allocazione di memoria (utilizzata dal gestore della memoria),
), contiene per ogni record le informazioni relative a:
o Allocazione della memoria ai processi
o Allocazione della memoria secondaria
o Attributi di protezione per l’accesso ad aree di memoria condivisa
o Informazioni necessarie per la gestione della memoria virtuale
Tabella dei dispositivi di I/O (utilizzata dal gestore di I/O), contiene per
ogni record le informazioni relative a:
1
Appunti di Sistemi Operativi Teoria
2
Appunti di Sistemi Operativi Teoria
Il Computer
Schema generale
CPU
Sono due le caratteristiche della CPU visibili ai programmi utente o al sistema operativo:
- I registri GPR (noti anche come general-purpose registers o come registri visibili
dagli utenti) che sono usati per memorizzare i dati, gli indirizzi, gli indici o lo stack
pointer durante l'esecuzione di un programma;
- I registri di controllo che contengono l'informazione necessaria a controllare il
funzionamento della CPU. Per semplicità l'insieme dei registri di controllo verrà
chiamato program status word (PSW) e i singoli registri verranno individuati
come campi della PSW.
PSW
3
Appunti di Sistemi Operativi Teoria
Program counter (PC), contiene l'indirizzo della prossima istruzione che deve essere
eseguita dalla CPU.
Il codice di condizione (CC) contiene un codice che descrive alcune caratteristiche
relative al risultato dell'ultima operazione aritmetica o logica eseguita dalla CPU (< 0 ,
= 0 , > 0).
Modalità, indica se la CPU è in esecuzione in modalità Kernel oppure in modalità
Utente
Informazioni di protezione della memoria,,serve a proteggere la memoria dato che
più processi possono accedere in contemporanea alla memoria e quindi bisogna
evitare che un processo modifichi il contenuto di una memoria utilizzata da un altro
processo. Contiene il campo base che indica l’indirizzo di partenza della memoria
allocate ad un programma ed il campo limite che contiene la dimensione della
memoria allocate al programma.
Maschera degli interrupt(IMP),indica quali interrupt sono consentiti in un dato
momento. Gli interrupt rilevabili sono detti abilitati mentre gli altri sono detti
mascherati o disabilitati.
Codice interrupt (IC),è un codice identificativo per gli interrupt.
MMU
L’MMU (Memory Management Unit) non è definibile ne Hardware ne Software ma un unità
customizzata a basso livello scritta in Assembly.Questa unità si occupa di effettuare la
traduzione degli indirizzi:
un indirizzo logico è l'indirizzo usato dalla CPU per fare riferimento ad un dato o ad
un'istruzione
un indirizzo fisico è l'indirizzo in memoria dove risiede il dato o l'istruzione richiesta
dalla CPU
La MMU si occupa proprio di "tradurre" un indirizzo logico in un indirizzo fisico. Inoltre, il
SO implementa la memoria virtuale usando l'allocazione della memoria non contigua e la
MMU. La tecnica della memoria virtuale consiste nel creare l'illusione di una memoria più
grande della reale memoria installata.
4
Appunti di Sistemi Operativi Teoria
Cache
La memoria cache contiene alcune istruzioni e valori di dati cui la CPU ha avuto accesso più
di recente. A causa della grande differenza di velocità tra cache e memoria centrale, per
ridurre il tempo di accesso effettivo alla memoria(EAT), si utilizza una gerarchia di memorie
cache. Esistono, infatti, cache di vari livelli che consentono di migliorare il tempo effettivo di
accesso alla memoria:
una cache L1 (cache di livello 1) è montata sul chip della CPU;
una cache L2 (cache di livello 2), più lenta ma più capiente della cache L1;
normalmente è presente anche una cache L3 ancora più capiente e lenta.
Quest'ultima è tipicamente esterna alla CPU.
Un'altra differenza è che la MMU viene sostituita da una configurazione parallela della MMU
e della cache L1. in questo modo alla cache L1 viene inviato un indirizzo logico piuttosto che
un indirizzo fisico eliminando di fatto il processo di traduzione degli indirizzi (da indirizzo
logico a indirizzo fisico).
Interrupt
Il Sistema operativo interviene su richiesta di un programma o in seguito ad un evento
che modifica o richiede di modificare lo stato del Sistema. Vi sono due modi per chiamare in
causa il Sistema operativo:
Tramite una chiamata al supervisore (supervisor call,svc)
Tramite una richiesta di intervento a seguito di un evento che avviene tramite il
meccanismo degli interrupt.
Gli interrupt vengono definiti eccezioni e si suddividono in:
Interrupt volontari, quando volutamente chiediamo l’intervento del Sistema
operativo;
Interrupt involontari, quando la richiesta di intervento non è voluta da noi utenti
(esempio carta esaurita nella stampante).
5
Appunti di Sistemi Operativi Teoria
chiamata di sistema corrisponde una Procedura di Libreria che ha come obiettivo quello di:
caricare i parametri della System Call al top dello Stack oppure nei registri.
Instanziare un istruzione chiamata TRAP che genera un Interrupt Hardware che
verrà poi intercettato dal gestore degli interrupt del Sistema Operativo. La Trap ha un
codice identificativo relativo alla chiamata di sistema che deve essere servita, e tutta
l’implementazione sottostante della Trap è nascosta interamente dalla Procedura di
Libreria rendendo le System call semplici chiamate di funzione.
Esempio:
Nel nostro programma ad un certo punto abbiamo una System call (es. una open), dietro la
system call vi è la “Procedura di libreria” che pone i parametri della System call al top dello
stack oppure nei registri per passare dalla modalità utente alla modalità kernel cambiando
il bit modalità all’interno del PSW, e instanzia l’istruzione Trap che verrà eseguita in modalità
Kernel ed invierà un interrupt che verrà intercettato dal gestore degli interrupt. Quest’ultimo
grazie al codice IRQ dell’interrupt generato scandisce il vettore degli interrupt, che si trova
sempre nelle prime locazione della RAM, e lo identifica. In questa locazione vi è il Link al
codice che deve essere eseguito (routine di Servizio) che è scritto in assembly e che
solitamente o si trova in memoria centrale oppure sul disco. Quando avviene il passaggio
dalla modalità utente alla modalità kernel la CPU salva il contesto ovvero salva il contenuto
del registro PSW esegue il codice e poi ripristina la situazione precedente , questo passaggio
prende il nome di context-switch.
Esistono varie classi di interrupt:
System call (esempio una oper,read,write)
Software (esempio divisione per 0)
Hardware (trap)
Timer, cioè scanditi da un certo tempo
6
Appunti di Sistemi Operativi Teoria
Ciclo di CPU
7
Appunti di Sistemi Operativi Teoria
Notazione Polacca-Postfista
Qualsiasi operazione deve effettuare la CPU è un operazione aritmetico-logica che può essere
Unaria o Binaria che opera sui dati. Tipicamente il modo con il quale queste operazioni
vengono trascritte attraverso una fase di compilazione etc.. è una rappresentazione in
notazione Polacca-Posfista ovvero dove gli operatori precedono gli operandi:
A + B +AB
Come si può vedere nella figura il gestore di interrupt si compone di tre passi.
1) Impostare il codice interrupt, Il primo passo imposta il codice dell'interrupt nel
campo IC del PSW in base alla causa dell'interrupt.
2) Salvare il PSW, Il secondo passo salva il contenuto del PSW in memoria in modo
tale che il kernel possa ricreare lo stato della CPU del programma interrotto
quando questo verrà ripristinato.
3) Caricamento del vettore di interrupt, Il terzo passo esegue l'appropriata routine
di servizio dell'interrupt nel kernel. In pratica viene servito l'interrupt. Nell'are del
vettore degli interrupt vi sono diversi vettori degli interrupt; in base alla classe di
interrupt si accede al vettore di interrupt corrispondente. L'informazione
contenuta nel vettore di interrupt viene caricata nel campo corrispondente del
PSW (si assume, per semplicità, che il vettore di interrupt abbia lo stesso formato
del PSW). Quindi nel terzo passo vengono caricate le informazioni dal vettore degli
interrupt nei campi program counter, maschera degli interrupt e modalità del PSW,
consentendo alla CPU di eseguire in modalità kernel la routine di servizio
8
Appunti di Sistemi Operativi Teoria
dell'interrupt.
Processi
Un processo è un programma in esecuzione che utilizza le risorse a esso allocate.
Solitamente, un'applicazione è costituita da più processi che interagiscono tra loro per il
raggiungimento di un obiettivo comune.
PCB
Per gestire più processi, ad ognuno di essi viene associato un descrittore (Process Control
Block). Esso contiene lo stato di un processo e lo stato della CPU relativo al processo se
la CPU non sta eseguendo le sue istruzioni.
In particolare, il PCB di un processo contiene due tipi di informazione:
Quelle necessarie quando il processo è in esecuzione (ambiente)
Quelle quando il processo non è in esecuzione (contesto)
Entrambe queste informazioni sono rappresentate dai registri presenti nel PSW che a
seconda dello stato del processo in esecuzione e non, prendono un nome differente.Tutti i
PCB sono mantenuti dal sistema operativo nella tabella dei processi.
Il PCB di ciascun processo contiene una tabella di puntatori a file descriptor nella tabella
dei file aperti, che contiene un file descriptor per ciascuno dei file aperti nel sistema con un
puntatore alla tabella degli i-node attivi. La tabella degli i-node contiene l’i-node per ogni file
che sia aperto una o più volte nel sistema. Un file può essere aperto una o più volte con
descrittori diversi anche dallo stesso processo.
9
Appunti di Sistemi Operativi Teoria
Spazi di indirizzamento
Lo spazio di indirizzamento rappresenta l’insieme di tutti gli indirizzi che vengono utilizzati o
che interagiscono con un processo. Esistono due tipologie di spazi di indirizzamento:
Spazio di indirizzamento logico, è l’insieme degli indirizzi generati dalla CPU per
eseguire un processo che dipende dallo spazio di indirizzamento fisico
Spazio di indirizzamento fisico, sono tutti gli indirizzi generati dall MMU e
memorizzati nei registri, la dimensione max dello spazio di indirizzamento fisico
dipende dalle linee dei bus di sistema
Se definiamo con v la dimensione dello spazio di indirizzamento logico e con f la dimensione
dello spazio di indirizzamento fisico allora:
La dimensione massima di v dipende dalla dimensione e quindi dal numero di bit
che costituiscono il registri di indirizzamento (IR) e dal PC, cioè se i è il numero di bit
che costituiscono l’IR allora la dimensione di v sarà al più pari a 2^i
La dimensione massima di f dipende dalla dimensione del bus di indirizzi, cioè se b
è il numero di line che costituiscono il bus indirizzi allora la dimensione di f sarà al
più pari a 2^b
Contesto di un processo
Il contesto consiste in una serie di informazioni tra cui il codice, i dati, lo stack, le
informazioni sulla memoria allocata al processo e le informazioni sulle risorse che utilizza.
In particolare, il contesto del processo si compone delle seguenti parti:
- Spazio di indirizzamento del processo: codice, dati e stack del processo.
- Informazione di allocazione della memoria: informazione relativa all'area di
memoria allocata al processo. viene usata dal MMU per la gestione della memoria.
- Stato delle attività di elaborazione del file: informazione relativa ai file usati.
- Informazione relativa all'interazione col processo: informazione necessaria
per controllare l'interazione del processo con gli altri processi.
- Informazione relativa alle risorse: informazione riguardante le risorse allocate
al processo.
- Informazioni varie: varie informazioni utili per il corretto funzionamento del
processo.
10
Appunti di Sistemi Operativi Teoria
ECB
Quando si verifica un evento, il kernel deve trovare il processo il cui stato è influenzato
dall'evento. L'operazione è effettuata mediante una ricerca nei campi delle informazioni
relative agli eventi dei PCB dei processi. Questa ricerca è costosa in termini di tempo, per cui
i SO usano vari schemi per velocizzarla. Uno di questi consiste nell'utilizzo dell'Event
Control Block (ECB).
Un ECB contiene tre campi:
- campo descrizione dell'evento, che descrive un evento
- campo ID del processo, che contiene l'ID del processo in attesa dell'evento
- campo puntatore all'ECB, che è necessario per inserire l'ECB di un processo
nella lista appropriata, in quanto il kernel può mantenere più liste separate di ECB
per ogni classe di evento
Multitasking
11
Appunti di Sistemi Operativi Teoria
Gestione di un processo
Prima di mandare un processo in esecuzione viene sempre effettuato un Context-switch,
ovvero un salvataggio del contesto nel PSW e nei registri GPR, salvataggio del processo
precedente per mandare in esecuzione il successivo. Subito dopo che il processo è andato in
esecuzione è necessario capire quanta CPU debba essere dedicata ad esso, ovvero la
Timeslice, la parte del sistema operativo che si dedica a questo è i Dispatcher, cioè il
distributore di risorse di tempo. Alla fine della sua esecuzione il processo ritorna nella lista
dei processi al fine di garantire il principio di equità. Nell’alternanza tra i processi vi sono
dunque segmenti di codice eseguiti dalla CPU (CPU Burst) durante lo stato di Running e
segmenti di codice eseguiti dall’unità di I/O (I/O Burst) durante la fase Blocked. Quindi un
processo può essere visto come una successione in alternanza di CPU Burst ed I/O Burst.
Vi si possono presentare due situazioni:
Se abbiamo molte esecuzioni di CPU-Burst anche di durata considerevole rispetto
all’I/O Burst, il processo che ne deduce viene identificato come CPU-Bound.
Viceversa se la frequenza e la durata degli I/O Burst è predominante rispetto a quella
di CPU-Burst, il processo prende il nome di I/O-Bound.
In una situazione ideale caratterizzata da un processore dedicato, un processo potrebbe
trovarsi in due stati:
Un processo attivo va in attesa, quando chiede un servizio alla CPU (in gergo si
dice fa I/O);
Un processo in attesa torna attivo, quando un servizio del sistema operativo è
terminato.
Questo è un esempio riguardante una situazione ideale composta da un solo processo. In
realtà i processi sono maggiori di uno quindi non è sufficiente ipotizzare un solo stato di
attività o inattività. Il miglior modo di rappresentare gli stati dei processi è un diagramma a
stati finiti (costituito da stati e da transizioni di stato).
N.B:Un processo si dice che faccia Busy waiting (attesa attiva) quando attende che una certa
condizione si verifichi alternando lo stato di ready e lo stato di running. Quando un processo
non fa busy waiting si trova in uno stato blocked.
12
Appunti di Sistemi Operativi Teoria
Stati di un processo
Diagramma a 4 stati
Un processo è bloccato (blocked) quando è in attesa che una risorsa da lui richiesta
gli venga allocata o quando è in attesa del verificarsi di un particolare evento.
Un processo è pronto (ready) quando può essere schedulato, cioè quando la richiesta
è soddisfatta o quando si è verificato l'evento che stava attendendo.
Un processo è in esecuzione (running) quando la CPU sta eseguendo le istruzioni del
processo stesso.
Un processo è terminato (terminated) quando viene portata a termine la sue
esecuzione o se, per qualche motivo, viene terminato dal kernel.
Transizioni di stato
(NEW) -> READY: un nuovo processo entra nello stato ready dopo che le risorse
richieste sono state allocate. In questo stato ci sono tutti i processi che si trovano in
memoria centrale.
N.B. per andare in esecuzione, il processo deve essere caricato in memoria centrale.
READY -> RUNNING: un processo può andare nello stato running solo se in
precedenza si trovava nello stato ready e ci va non appena viene completato il
dispatching. In pratica un processo va in esecuzione non appena gli viene passato il
controllo della CPU. Dallo stato running può raggiungere tutti gli altri stati.
RUNNING -> TERMINAZIONE: un processo passa dallo stato running a quello di
terminazione quando viene portata a termine l'esecuzione del programma. Le cause
che portano alla terminazione di un programma sono molteplici (es: auto-
terminazione, terminazione richiesta dal processo padre, eccesso di utilizzo di una
risorsa, condizioni anomale durante l'esecuzione, interazione non corretta con altri
processi). Quando un processo è terminato, vengono liberate tutte le risorse che gli
erano state assegnate.
RUNNING -> READY: un processo passa dallo stato running a quello ready quando
13
Appunti di Sistemi Operativi Teoria
Diagramma a 6 stati
Quando si verifica un degrado delle prestazioni può essere opportuno swappare uno o più
processi nell’area di swap del disco, vengono così aggiunti altri 2 nuovi stati:
Blocked swapped (bloccato e sospeso), il processo è in fase di I/O e può accadere
che il sistema debba liberare un po’ di memoria e quindi swappa il processo sul disco.
Ready swapped (pronto e sospeso), il processo è pronto per l’esecuzione ma non vi
è abbastanza spazio in memoria centrale e quindi viene swappato sul disco in attesa
che si liberi spazio.
Transizioni di stato
Blocked swapped -> blocked, il processo non ha terminato le operazioni di I/O ma la CPU
si accorge che vi è abbastanza spazio in memoria centrale e quindi lo carica nello stato
blocked.
Blocked swapped -> ready swapped, il processo ha terminato le operazioni di I/O ma non
vi è ancora abbastanza spazio in memoria centrale quindi passa in ready ma non swappato.
14
Appunti di Sistemi Operativi Teoria
Casi studio
Processi in Unix
In unix esistono due tipologie di processi: processi utente e processi kernel.
Un processo utente esegue un’elaborazione per l’utente ed è associato al terminae di
controllo dell’utente.
Un processo daemon è un processo che non dipende dal terminale di controllo
dell’utente. Viene eseguito in background e generalmente esegue funzioni di Sistema
(es. Gestione della rete).
I processi kernel eseguono il codice del kernel e riguardano le operazioni di
background del kernel come lo swapping, sono creati automaticamente all’avvio del
Sistema e possono richiamare le funzioni del kernel o far riferimento alle strutture
dati del kernel senza dover effettuare nessuna system call.
Unix utilizza due strutture dati per memorizzare I dati di controllo relative ai processi:
Struttura proc, contiene l’id del processo, lo stato del processo, la priorità, le
informazioni relative all’interazione con altri processi, il descrittore dell’evento per il
quale un processo bloccato è in attesa, la maschera per la gestione dei segnali e le
informazioni relative alla gestione della memoria.
U-Area, Quando un processo va in esecuzione viene memorizzata un immagine del
processo in memoria che è organizzata in due parti:
Area utente, che contiene Codice,Dati e Stack
Area Kernel che contiene il Kernel Stack e l’U-Area
L’User-Area contiene :
PCB, che contiene lo stato della CPU per il processo
bloccato.
Il puntatore alla struttura proc, che memorizza i dati
relativi alla schedulazione
Gli ID degli utenti e del gruppo
Informazioni sui segnali
Informazioni sui file aperti
Terminale collegato al processo
Utilizzo della CPU da parte del processo
E’ implementata sequenzialmente e il vuoto centrale è creato in modo tale che sia permesso:
ai dati di espandersi verso il basso ed allo stack di espandersi verso l’alto. Usando questa
descrizione si immagina un processo interamente caricato in memoria, in realtà questo non
avviene poiché non verrebbe garantito il Multitasking.
La struttura proc è Sempre in memoria, mentre l’u-area necessita di stare in memoria
15
Appunti di Sistemi Operativi Teoria
Processi in Linux
La versione 2.6 di Linux supporta il modello di thread 1:1, ovvero I thread di livello kernel.
Utilizza un descrittore di processo per memorizzare tutte le informazioni riguardanti un
processo o un thread. Sia I processi che I thread sono create utilizzando la system call fork()
o vfork().
Processi in Windows
Window considera un processo come un unità di allocazione delle risorse e usa un thread
come unità per la concorrenza. Di conseguenza un processo Windows per essere eseguito
deve contenere almeno un thread. Windows supporta la nozione di job come metodo di
gestione di un gruppo di processi. Un job è rappresentato da un oggetto propriamente detto
job, che contiene le informazioni come gli handle ai processi in esso contenuti, il limite di
tempo di CPU per il job, il limite di tempo di CPU per ogni processo ecc. Un processo può
appartenere ad un solo job, tutti I processi figli appartengono allo stesso job.
16
Appunti di Sistemi Operativi Teoria
Thread
17
Appunti di Sistemi Operativi Teoria
Thread utente
I thread di livello utente sono implementati da una libreria di thread, che viene linkata al codice
del processo. In questo tipo di thread il kernel non viene coinvolto ed è la libreria stessa
che gestisce l'alternanza dell'esecuzione dei thread nel processo. In questo modo, il kernel
non è a conoscenza della presenza dei thread di livello utente in un processo; il kernel vede
solo il processo.
Thread Kernel
Un thread di livello kernel è implementato dal kernel, dunque la creazione, la terminazione
e il recupero dello stato di un thread kernel sono effettuati mediante system call.
L'overhead dovuto alla commutazione, nel caso di thread di livello kernel, risulta 10 volte più
veloce rispetto alla commutazione tra processi.
Thread Ibridi
Un modello del genere implementa sia i thread di livello utente che i thread di livello kernel
e anche un metodo per associare i thread di livello utente ai thread di livello kernel.
La libreria di thread crea thread utente in un processo e, a ogni thread utente, associa un
thread control block (TCB). Il kernel crea i thread kernel in un processo e, a ogni thread
kernel, associa un kernel thread control block (KTCB). Ci sono tre metodi per associare i
thread di livello utente ai thread di livello kernel.
molti a uno - il kernel crea un singolo thread kernel nel processo e tutti i thread
utente creati nelprocesso sono associati con l'unico thread kernel. L'effetto creato è
simile ai semplici thread utente. I thread utente non possono essere paralleli,
l'overhead è basso e il blocco di un thread porta al blocco di tutti i thread nel processo.
uno a uno - ogni thread utente è mappato permanentemente su un thread kernel.
L'effetto è simile ai semplici thread kernel. I thread possono essere eseguiti in
parallelo su diverse CPU, la commutazione produce un overhead più elevato perché
è eseguita dal kernel, il blocco di un thread non blocca tutti gli altri thread perché i
thread sono mappati su diversi thread kernel.
uno a molti - ad ogni thread utente è permesso di essere mappato su differenti thread
kernel in momenti diversi. Questo modello consente di sfruttare il parallelismo e di
generare poco overhead. Tuttavia, l'implementazione risulta più complessa.
18
Appunti di Sistemi Operativi Teoria
Scheduler
Visto che un SO deve fornire una giusta combinazione tra prestazioni del sistema e
servizio utente, occorrono diversi scheduler (cioè diversi algoritmi) ognuno dei quali può
utilizzare una combinazione di diverse politiche di scheduling. Infatti, in un moderno SO,
possono essere impiegati fino a tre scheduler:
a. Scheduler a breve termine
b. Scheduler a medio termine
c. Scheduler a lungo termine
19
Appunti di Sistemi Operativi Teoria
Politiche di Scheduling
Esistono diverse politiche di scheduling, si possono classificare in tre categorie
1) Preemptive e non preemptive
2) Con priorità o senza priorità
20
Appunti di Sistemi Operativi Teoria
21
Appunti di Sistemi Operativi Teoria
Questa politica schedula il processo con il rapporto di risposta maggiore. Qualora questo
rapporto fosse uguale ad 1 vorrebbe dire che non vi sono processi concorrenti, il processo è
solo. Generalmente questo valore è > 1.
Il rapporto di risposta è definito: tempo di tournaround normalizzato.
Politiche preemptive
La politica di scheduling preemptive (con prelazione) dà la possibilità di interrompere il
processo correntemente in esecuzione a favore di un altro processo. Essa seleziona un
processo e lo lascia in esecuzione per una certa quantità di tempo massima. Se il processo,
alla fine del tempo concessogli, è ancora in esecuzione, allora viene sospeso e lo scheduler
seleziona un altro processo a cui attribuire l'uso della CPU. Le tre politiche di scheduling
preemptive sono:
- Scheduling Shortest Job First (SJF) nella versione preemptive (SRTF)
- Scheduling Round-Robin con Time-Slicing (RR)
- Scheduling Least Completed Next (LCN)
22
Appunti di Sistemi Operativi Teoria
23
Appunti di Sistemi Operativi Teoria
questo algoritmo privilegia i processi CPU bound perché utilizza l'intero quanto assegnato.
Il round robin è facile da implementare: lo scheduler mantiene una coda di processi in stato
ready e seleziona semplicemente il primo processo in coda e quando scade il quanto il
processo viene messo in fondo alla lista. L'unica questione riguardo a questo algoritmo è la
durata del quanto: assegnare un quanto troppo breve provoca troppi context switch e
peggiora l'efficienza della CPU (overhead troppo elevato), ma assegnarlo troppo alto può
provocare tempi di risposta lunghi per richieste interattive brevi. Avendo q come quanto e n
processi nessun processo attenderà per più di (n-1)q quanti di tempo. Se q = inf la politica
round robin si trasformerebbe in una politica FCFS.
IL round robin può essere implementato in due versioni:
Senza priorità, secondo cui la ready queue è mantenuta come una coda FIFO, quindi
viene selezionato un processo e gli viene assegnata la risorsa CPU, vi è un
avvicendamento continuo dei processi dalla ready queue all’esecuzione.
Con priorità, dà la possibilità di distinguere tra processi interattivi e processi
batch. In questo caso la ready queue non è mantenuta come una coda FIFO ma come
una coda a priorità per cui viene selezionato il processo a massima priorità, gli viene
assegnata la timeslice di CPU dopodichè ritorna nella coda, nella giusta posizione.
24
Appunti di Sistemi Operativi Teoria
25
Appunti di Sistemi Operativi Teoria
Scheduling a lotteria
Lo scheduling a lotteria è una tecnica utile per la condivisione di una risorsa in maniera
probabilisticamente equa. I 'biglietti' sono distribuiti a tutti i processi che condividono una
risorsa (ad esempio il tempo di CPU). Quando lo scheduler deve selezionare un processo a
cui attribuire la CPU, viene scelto a caso un biglietto e il processo che lo possiede ottiene la
risorsa. Per migliorare le prestazioni, ai processi più importanti possono essere assegnati
biglietti extra, per aumentare la loro probabilità di vincere. Inoltre i processi possono
scambiarsi i biglietti se lo desiderano per avvantaggiare i processi con la quale cooperano per
raggiungere un obiettivo comune.
Scheduling garantito
Questo tipo di scheduling promette ad un utente una certa quality of service, cioè assegna
un tempo di CPU, ad esempio 1/n di quello a disposizione. Questa quantità di tempo viene
fornita in timeslice e per renderci conto di quanto tempo viene dedicato ad un processo viene
utilizzato un contatore del tempo di CPU utilizzato da quando il processo viene lanciato. Si
può quindi attribuire ad ogni processo una priorità pari a:
Scheduling real-time
Nello scheduling real-time il tempo gioca un ruolo essenziale perché si devono rispettare delle
scadenze chiamate deadline.
Per ogni processo possono essere specificati due tipi di deadline:
- la scadenza d'inizio, cioè il minimo istante entro cui le operazioni del processo devono
cominciare
26
Appunti di Sistemi Operativi Teoria
- la scadenza di fine, cioè il tempo entro il quale le operazioni del processo devono
terminare
I Sistemi real-time sono classificati in:
- Hard real-time: garantiscono che i compiti critici sono completati in un intervallo limitato;
cioè rispetta le deadline in maniera garantita.
- Soft real-time: sono meno restrittivi; cioè che pur avendo scadenze da rispettare, se alcuni
processi non lo fanno occasionalmente, sono tollerati; cioè rispetta le deadline in maniera
probabilistica.
I processi vengono gestiti in maniera periodica, per esempio ogni 5 minuti (come i video on-
demand). Un modo per assegnare priorità ai processi avviene in base al valore del periodo
(rate monotonic scheduling) cioè in base alla frequenza. Per questo motivo verranno
schedulati prima i processi che hanno una frequenza più alta (periodo minore) rispetto a
quelli che hanno una frequenza più bassa(periodo maggiore).
Criterio di schedulabilità
Per qualsiasi algoritmo di scheduling di n Task Periodici la condizione necessaria purchè I
processi possano essere eseguiti è:
“Sommatoria Ci/ti <= 1”
27
Appunti di Sistemi Operativi Teoria
Scheduling in Unix
Unix è un SO time-sharing puro che usa una politica di scheduling multilivello adattivo,
quindi viene associata ad ogni processo una priorità, che in Unix è di tipo numerica: valori
alti corrispondono a basse priorità e viceversa. Vengono schedulati i processi con priorità
maggiore (cioè col valore vicino allo 0). In Unix, viene usata la seguente formula per variare
la priorità di un processo:
Formula
dove:
- f è il tempo di CPU usato recentemente
- nice è una system call che permette di modificare la priorità del processo chiamante
28
Appunti di Sistemi Operativi Teoria
Sezione critica
La sezione critica è una parte di codice importante formata da istruzioni atomiche o
indivisibili che va salvaguardata dalla schedulazione.
Si suddivide in :
Entry section, permette un entrata controllata alla sezione critica
Exit section, permette di uscire dalla sezione critica e quindi ripristinare le condizioni
iniziali.
Un altro aspetto importante risulta essere la portabilità ovvero se il codice sviluppato può
essere eseguito sia sui sistemi monoprocessore che sui sistemi multiprocessore nei quali il
codice verrà splittato tra i vari processori e deve essere indipendente dalla velocità di ogni
singolo processore. Quindi il problema consiste nella progettazione dell’entry-section e dell’
exit -section.
Per una corretta implementazione si richiede il soddisfacimento di quattro condizioni.
29
Appunti di Sistemi Operativi Teoria
Race condition
Nell'ambito dei SO, le race condition (o corse critiche) sono delle situazioni che si verificano
quando due o più processi stanno leggendo o scrivendo un qualche dato condiviso e il
risultato finale dipende dall'ordine in cui vengono schedulati i processi. In pratica si ha una
race condition quando due processi accedono alla stessa parte di memoria
contemporaneamente.
Per evitare le race condition bisogna assicurarsi che solo un processo alla volta possa
accedere e modifica i dati in comune. Questa condizione richiede una forma di
sincronizzazione tra processi.
Condizioni di Bernstein
Dato un programma sequenziale è possibile stabilire un criterio per determinare se più
istruzioni possono essere eseguite concorrentemente. Tale criterio è espresso dalle condizioni
di Bernstein. Mediante le condizioni di Bernstein è possibile prevenire le race condition,
verificando per ogni coppia di processi se vengono soddisfatte le suddette condizioni.
Prima di elencare tali condizioni è necessario fornire alcune definizioni.
indichiamo con A, B, C, < , Y, Z le aree di memoria
chiamiamo dominio (i) le aree di memoria da cui dipende un istruzione i (quelle a cui
accede in lettura)
chiamiamo range (i) le aree di memoria modificate dall'istruzione I (quelle a cui accede
in scrittura)
E' lecito eseguire concorrentemente due istruzioni i,y se valgono le seguenti condizioni:
1. range(i) range(y) = Ø agiscono su aree di memoria differenti
2. range(i) dominio(y) = Ø l'area su cui agisce un'istruzione non modifica l'area da
cui
dipende l'altra
3. dominio(i) range(y) = Ø viceversa della condizione 2
30
Appunti di Sistemi Operativi Teoria
Approccio Hardware
Nell'approccio hardware, la sincronizzazione tra processi viene implementata utilizzando
istruzioni macchina speciali fornite dall'architettura unite all'uso di variabili condivise,
chiamate variabili di lock oppure una soluzione consiste nell’abilitazione/disabilitazione
degli Interrupt..
31
Appunti di Sistemi Operativi Teoria
bloccherebbe il sistema.
Questa soluzione non è multiprocessore poiche gli interript possono essere intercettati e
gestiti solo da una cpu per volta.
Un'altra soluzione è utilizzare variabili speciali di basso livello con le quali è possibile gestire
l’accesso alla sezione critica in modo più controllato e più portabile sui sistemi multicore.
Queste variabili sono dette variabili di lock.
Variabili di lock
Una variabile di lock è una variabile a due stati - aperto e chiuso - utilizzata dai processi per
accedere alle sezioni critiche. Quando un processo vuole eseguire una sezione critica, legge
il contenuto della variabile di lock e:
- se il lock è aperto (valore 0), il processo imposta il valore del lock a chiuso (valore 1) ed
esegue la sezione critica, dopodichè, al termine, lo imposta dinuovo ad aperto
- se il lock è chiuso (1), il processo attende che diventi aperto (0)
L'uso di questa variabile presenta un problema: supponiamo che un processo legga la
variabile di lock e vede che è aperta (0), ma prima che possa chiuderla (1), viene schedulato
un altro processo che va in esecuzione e chiude la variabile lock (1); quando il primo processo
ritorna in esecuzione, chiuderà anch'esso la variabile lock (1) e i due processi saranno
contemporaneamente nella sezione critica. Per evitare race condition nell'impostazione della
variabile di lock, viene utilizzata un'operazione indivisibile per la lettura e la chiusura.
Di seguito, vengono illustarte l'uso di due istruzioni indivisibili, chiamate istruzioni test-and-
set e swap.
L’istruzione esamina il valore di una variabile globale condivisa e la setta, se questo valore è
0 lo setta ad 1 e ritorna TRUE altrimenti ritorna FALSE.
Analizziamo il comportamento di un processo Pi che vuole entrare in sezione critica.
32
Appunti di Sistemi Operativi Teoria
SPIEGAZIONE
Il processo Pi cicla facendo busy waiting sulla
valutazione della Test-and-set (!testset(lock)).
Lock è 0 e quindi chiamando la testset(0), imposta
lock a 1 e ritorna TRUE ma (!TRUE) è FALSE e
quindi esce dal while.
Il primo processo che riesce a chiamare la testset
sulla lock è quel processo che entra in sezione
critica. All’uscita dalla sezione critica la variabile
lock viene risettata a 0 per permettere ad un altro
processo di entrare in sezione critica.
Valutazione delle condizioni di sincronizzazione
Mutua esclusione garantita, poiché in sezione critica entra solo chi ha lock = 1 ed è
un solo processo, gli altri faranno busy waiting.
Il progresso è garantito, poiché se un processo non vuole entrare in sezione critica
non esegue il while.
L’attesa limitata è garantita a patto che non si verifichino fault.
N.B.: L’istruzione funziona a patto che la test-and-set sia un istruzione atomica cioè sia
indivisibile.
Un'altra soluzione simile è l’istruzione XCHG.
33
Appunti di Sistemi Operativi Teoria
34
Appunti di Sistemi Operativi Teoria
35
Appunti di Sistemi Operativi Teoria
Approccio Software
Gli approcci software si basano su algoritmi che tendono a garantire le condizioni necessarie
per una corretta gestione delle sezioni critiche.
Primo Tentativo
La variabile turn è una variabile
condivisa che indica quale sarà il
prossimo processo ad accedere alla
sezione critica. Essa può assumere
due valori, o il valore 1 o il valore 2.
Prima che i due processi, P1 e P2,
vengano creati, viene inizializzata a 1.
Il processo P1 può entrare nella
sezione critica se turn=1, mentre P2
può entrarci se turn=2.
SPIEGAZIONE
Per scelta inizialmente si concede il turno al processo P1 quindi turno = 1. Il processo P1
setta la variabile turno = 1, questo mostra la sua intenzione di entrare in sezione critica,
prima di farlo verifica con un while se l’altro processo (P2) è in sezione critica, cioè se “Turno
= 2” se è vero non fa nulla.
La variabile turno essendo una variabile globale inizialmente ogni processo la setta al proprio
turno e lo scheduler sceglie un processo e lo manda in esecuzione.
Potrebbe però verificarsi un problema. Se il processo P1 viene scelto dallo scheduler, imposta
turno = 1 e poi in virtù della timeslice passa ad un altro processo che ha il tempo di settare
turno = 2, il procvesso P1 va in esecuzione trova turno = 2 per via dell’ultima modifica e
sebbene sia il suo torno di esecuzione non fa nulla poichè è il turno di P2 secondo la variabile
turno. Termina la timeslice dedicata a P1, P2 ha turno = 2 ed entra in sezione critica.
E’ assolutamente imprevedibile sapere quale sia l’ordine di esecuzione tra I processi. Tutto
dpende dallo scheduler e non dall’ordine di sincronizzazione. Quello che è invece importante
è che il primo dei due che entra in sezione critica ci rimanga perchè finche il processo in
sezione critica non termina la variabile turno non viene modificata. Solo all’uscita dalla
sezione critica viene assegnato il turno all’altro processo.
Per come è strutturato vi è un alternanza stretta tra i processi.Questa alternanza funziona
fintantochè I processi coinvolti vogliono entrare in sezione critica, poichè se uno dei due
36
Appunti di Sistemi Operativi Teoria
processi non necessita di entrare in sezione critica secondo quest’algoritmo seta turno = se
stesso e turno rimane settato a quell processo fintantochè non entra in sezione critica.
Valutazione delle condizioni di sincronizzazione
Mutua esclusione è garantita poiché vi è la variabile turno che indica il turno del
processso per entrare in sezione critica
Il progresso non è garantito, poiché quando un processo non necessita di entrare
in sezione critica blocca l’avanzamento dell’altro processo.
L’attesa limitata non è garantita, poiché un processo potrebbe attendere un tempo
indefinito che l’altro processo gli permetta di accedere in sezione critica.
Secondo tentativo
SPIEGAZIONE
Inizialmente entrambi i flag sono false, il processo P1 prima di entrare in sezione critica
verifica il flag di intenzione dell0altro processo, cioè verifica se P2 vuole entrare in sezione
critica. Se è vero gli concede l’entrata (cortesia). Se invece P2 non vuole entrare, P1 setta il
suo flag = true, entra in sezione critica e soltanto all’uscita risetta il flag = false.
E’ stata abolita la variabile turno cioè significa che questa soluzione non prevede un
alternanza stretta ma rende imprevedibile sapere chi sarà il processo ad entrare in sezione
critica.Può accadere che un processo entri sempre in sezione critica perche ne richiede
sempre l’intenzione.
Valutazione delle condizioni di sincronizzazione
Mutua esclusione non garantita, quando i due processi tentano di entrare allo
stesso tempo nelle rispettive sezioni critiche. Sia c1 che c2 saranno pari a 1 (poiché
nessuno dei due processi si trova in sezione critica) per cui entrambi i processi
entreranno nelle sezioni critiche. Per evitare questo problema, le istruzioni ‚while c2 =
0 do { niente };‛ e ‚c1 := 0;‛ nel processo P1 possono essere invertite. Analogamente, le
37
Appunti di Sistemi Operativi Teoria
istruzioni ‚while c1 = 0 do { niente };‛ e ‚c2 := 0;‛ nel processo P2 possono essere invertite.
In questo modo c1 sarà impostato a 0 prima che P1 controlli il valore di c2 e dunque
entrambi i processi non potranno trovarsi nelle rispettive sezioni critiche allo stesso
tempo.
Progresso è garantito, Se un processo fallisce all'esterno della sua sezione critica,
compreso il codice per modificare il flag, allora l'altro processo non è bloccato: infatti,
l'altro processo può entrare nella propria sezione critica tutte le volte che vuole, perché
il flag dell'altro processo è sempre falso.
L’attesa limitata non è garantita, Se un processo fallisce all'interno della propria
sezione critica, o dopo aver messo il flag a vero prima di entrare, allora l'altro processo
è bloccato per sempre.
Dekker
38
Appunti di Sistemi Operativi Teoria
critica a TRUE (C1 = 0) ma lo fa ancora all’interno del while (C2 = 0), però se P2 è uscito dalla
sezione critica significa che C2 = 1, quindi il while fallisce e P1 entra in sezione critica.
All’uscita cede il turno a P2 e riisetta la sua intenzione a FALSE.
L’idea è di avere un alternanza sul turno ma effettuare il controllo sull’intenzione di entrare
in sezione critica.
Valutazione delle condizioni di sincronizzazione
Mutua esclusione è garantita, perché quando un processo è in sezione critica il
proprio flag è settato a 0 e il turno è settato a se stesso. Possono esserci piu processi
con il flag settato a 0 però solo un processo avrà il turno per entrare
Il progresso è garantito poiché quando un processo non vuole entrare in sezione
critica non dichiara la sua intenzione di volerci entrare e quindi non blocca gli altri
processi.
L’attesa limitata non è garantita poiché se avviene un fault all’interno della sezione
critica l’altro processo in attesa non avrà mai il turno questo può avvenire perche
questo codice viene scritto dal programmatore.
39
Appunti di Sistemi Operativi Teoria
Peterson
L'algoritmo di Peterson,
così come l'algoritmo di
Dekker, risolve il problema
della mutua esclusione ma
in un modo più semplice
rispetto all'algoritmo di
Dekker.
Al posto dei flag C1 e C2
troviamo Flag[0],Flag[1]
rispettivamente per I
processi P1 e P2 che
indicano le intenzioni di
voler o meno entrare in
sezione critica. Turno non
viene inizializzato inizialmente ma vengono settati entrambi i flag a FALSE. Quindi la scelta
del processo da eseguire è demandato allo scheduler che sceglierà l’uyltimo processo poichè
sarà quell processo ad avere il turno settato a se stesso.
SPIEGAZIONE
Entriamo nel Parbegin, il processo P1 dichiara l’intenzione di entrare in sezione critica
(Flag[0] = TRUE) , dopodichè cede il turno a P2 (cortesia).
Ora verifica se è il turno di P2 e il processo P2 ha intenzione di entrare in sezione critica
(Flag[1] = TRUE) se entrambe sono vere allora P1 attende che P2 finisca.
N.B .: se il processo P2 NON vuole entrare in sezione critica (Flag[1]= FALSE) ma P1 gli ha
ceduto il turno, il while fallisce e P1 va in sezione critica. Cioè la differenza di questo algoritmo
dall’algoritmo di DEKKER è che il processo NON si blocca anche se il turno è di P2.
Quindi il punto focale è l’AND logico poichè per entrare in sezione critica bisogna verificare
entrambe le condizioni, non solo, si entra anche se il turno è di un altro processo che però
non ha intenzione di entrare.
L’importanza della variabile turno è ridotta ed è importante nel caso in cui entrambi i processi
hanno intenzione di entrare in sezione critica poichè in questo caso prima entra uno e poi
l’altro.
Valutazione delle condizioni di sincronizzazione
Tutti i requisiti sono garantiti se non avvengono fault all’interno della sezione critica
40
Appunti di Sistemi Operativi Teoria
Panettiere
41
Appunti di Sistemi Operativi Teoria
entrato e ne uscito dalla sezione critica. Pi ora verifica se (NUMBER[j],j) < (NUMBER[i],i),
poiché se fosse vero il processo Pj avrebbe priorità più alta. La verifica avviene con una coppia
poiché potrebbe accadere che il processo Pi abbia scelto lo stesso numero del processo Pj
questo discende dal fatto che NUMBER è GLOBALE, in questo caso l’ordine verrebbe stabilito
solo n base agli indici i e j. Quando, infine, Pi esce dalla sezione critica setta NUMBER[i]=0
che indica la non intenzione a voler entrare in sezione critica e termina.
Valutazione delle condizioni di sincronizzazione
Soddisfa tutte e tre le condizioni
Semafori
Un semaforo è un costrutto linguistico che viene utilizzato per effettuare la sincronizzazione
tra i processi indipendentemente dalla velocità dei processori.
42
Appunti di Sistemi Operativi Teoria
Semafori binari
Un semaforo binario è una struttura di sincronizzazione dove ogni oggetto ha due campi:
Un contatore, serve a tenere conto delle risorse disponibili incrementandole o
decrementandole;
Una coda, è una lista di PCB per gestire i processi, mantenuta FIFO per default, ma
può anche essere una coda a priorità e quindi avere un Heap.
Le operazioni che si possono effettuare sul semaforo sono:
Wait, controlla se il valore del semaforo è > 0. In caso affermativo, decrementa il valore
del semaforo e consente al processo di proseguire la sua esecuzione; altrimenti, blocca
il processo sul semaforo.
Signal , controlla se ci sono processi bloccati sul semaforo. In caso affermativo,
l'operazione attiva un processo bloccato sul semaforo; altrimenti incrementa il valore
del semaforo di un'unità.
Entrambe queste operazioni sono operazioni Atomiche cioè indivisibili, questo è
realizzabile:
Disabilitando gli interrupt, soluzione non portabile su sistemi multiprocessore;
Usando la Test-set-lock, cioè un entry section e un exit section sia per la wait che
per la signal.
43
Appunti di Sistemi Operativi Teoria
Invarianza
Siano:
nP, il numero di wait completate
nV, il numero di signal completate
INIT, il valore iniziale del semaforo (S)
Vale:
nP <= nV + INIT
Cioè il numero di wait completate sarà al più uguale al numero di signal completate più INIT,
poiché possiamo fare tante wait quante sono INIT ma possiamo anche portare il valore del
semaforo in negativo. Per riprendere il valore positivo dobbiamo effettuare altrettante signal.
Il valore iniziale del semaforo (INIT) può essere > 1, in questo caso significa che o ci sono più
risorse disponibili condivise o la stessa risorsa può essere condivisa tra N processi. In questo
caso il semaforo è detto : Semaforo Contatore.
44
Appunti di Sistemi Operativi Teoria
Semafori Contatori
Il semaforo contatore è un semaforo che permette di avere un contatore indicante il numero
di processi in attesa nella coda, per farlo la soluzione precedente è cosi modificata:
N.B. : nella wait la condizione dell’IF è minore stretto poiché altrimenti il processo Pi con S=1
si autobloccherebbe alla prima iterazione.
Wait: in questo caso ogni volta che un processo viene bloccato in attesa nella coda deve
prima decrementare S. Solo un processo decrementa ed entra in sezione critica, tutti gli altri
restano in attesa. In questo modo il valore assoluto del contatore (S) ci fornirà il numero
di processi in coda.
Signal: in generale prima si esegue un azione che consente la prosecuzione di altri processi
(risveglio) e successivamente si incrementa. In questo caso essendoci più risorse viene prima
incrementato il contatore e poi controllato lo stato per risvegliare il processo.
Semafori mutex
Esso è inizializzato a 1 ma può assumere solo i valori 0 e 1 durante l'esecuzione del
programma.
Le operazioni wait e signal sono differenti rispetto a quelle eseguite su un semaforo normale:
- l'istruzione ‚S = S - 1‛ è sostituita dall'istruzione ‚S = 0‛
- l'istruzione ‚S = S + 1‛ è sostituita dall'istruzione ‚S = 1‛
Ogni volta che un processo ha bisogno di accedere ai dati condivisi, acquisisce il mutex
(mutex_lock); quando l'operazione è terminata, il mutex viene rilasciato (mutex_unlock),
permettendo ad un altro processo di acquisirlo per eseguire le sue operazioni. La differenza
importante dei semafori Mutex da quelli binary è che un processo in attesa su un semaforo
45
Appunti di Sistemi Operativi Teoria
binario puà eventualmente essere risvegliato da un qualsiasi altro processo mentre nei
semafori mutex il processo che effettua la lock è lo stesso che può effettuare l’unlock.
Monitor di Hoare
I monitor sono costrutti linguistici ad alto livello che permettono di definire operazioni di
sincronizzazione in modo più controllato ed esteso.
Un monitor può essere visto come una classe al cui interno vi sono procedure,variabili e
strutture dati non accessibili direttamente dai processi. Le procedure del monitor sono
eseguite in mutua esclusione, cioè il monitor all’accesso,implicitamente, effettua delle
system call al sistema operativo il quale poi governa l’acceso alle procedure. Ovviamente,
essendo garantita la mutua esclusione il rpimo processo ceh accede alla procedura la esegue
mentre il resto si accoda creando una “coda di accesso al monitor”.
Il processo all’interno del monitor potrebbe rimanere Bloccato o Sospeso da altri eventi che
accadono all’interno del monitor. In tal caso il processo che era in esecuzione resta bloccato
all’interno del monitor ma si permette l’accesso e l’esecuzione di un altro processo in coda
fuori dal monitor. Quindi si avranno 2 processi all’interno del monitor, ma uno solo in
esecuzione.
Le proceduer definite all’interno del monitor sono le Sezioni critiche. Quindi tutti il codice
46
Appunti di Sistemi Operativi Teoria
critico è portato all’interno del monitor il quale è scritto una sola volta e validato, per poi
successivamente venire solo utilizzato.
Un processo può Sospendersi o Bloccarsi per due motivi:
In seguito ad un evento
In seguito all’intervento dello scheduler
All’interno del monitor per verificare se un dato evento si è verificato o meno, non essendoci
i semafori, si utilizzano le variabili di condizione.
Variabili di condizione
Le variabili di condizioni sono strutture dati contenenti una coda di processi in attesa sulla
variabile di condizione. Sono dette variabili poiché il numero di processi in attesa può variare
ma in realtà sono liste di PCB relativi ai processi.
La variabile di condizione esiste anche da sola. Da sola, però, non garantisce la mutua
esclusione. Per farlo bisogna associarla ad un mutex , cioè a quel meccanismo di
sincronizzazioneche permette di entrare o meno in sezione critica e non contempla
necessariamente la coda dei processi in attesa che il semaforo si liberi.
Essa può essere utilizzata al di fuori del monitor, ovviamente non di tipo Condition, ed è
associabile ad una condizione che non è implicitamente definita all’interno di essa ma deve
essere definita esplicitamente dal programmatore.
L’idea è:
Se una certa condizione è verificata allora entro in sezione critica
Altrimenti attendo (wait sulla variabile di condizione)
La condizione da valutare può essere:
Il valore di un contatore
Un valore booleano
Tipicamente si valuta una variabile che deve essere verificata da minimo due processi, di
conseguenza la variabile che deve essere valutata nella condizione a cui associamo la
variabile di condizione deve essere globale.
Sorge, quindi, il problema di dover garantire la mutua esclusione, poiché la variabile di
condizione di per sé ha solo la coda dei processi in attesa su di essa, non ha nessun
meccanismo di sincronizzazione. Per ovviare a ciò la si associa ad un Mutex che è può
assumere solo due valori: 0 e 1.
47
Appunti di Sistemi Operativi Teoria
Monitor di Lampson/Redell
In Java viene utilizzata una versione diversa di Monitor. Invece di utilizzare la primitiva
Signal viene utilizzata Notify che non risveglia il processo ma notifica la disponibilità della
risorsa. Quando un processo in esecuzione nel monitor esegue Notify(c) manda un segnale
alla coda corrispondente a c.
Il processo,quindi, resta in attesa che una certa condizione si verifichi (contatore == 0 oppure
contatore == N), poihè non è un altro processo ad effettuare il risveglio ma bensì la politica
di scheduling, questo rende imprevedibile sapere “quando” avverrà la riattivazione.
E’ possibile introdurre:
un controllo sul tempo associato ad ogni condizione: un processo che ha aspettato
per il tempo massimo stabilito, è posto in ready queue indipendentemente dalla
48
Appunti di Sistemi Operativi Teoria
condizione.
aggiungere la primitiva broadcast, che ha l’effetto di mettere in ready queue tutti i
processi in attesa su una condizione. Utile nelle situazioni in cui un processo non sa
quanti processi devono essere riattivati.
Regione Critica
Con il costrutto ad alto livello region possiamo avere l'accesso a tali variabili garantendo
mutex e non busy waiting.
Dichiaro la variabile V di tipo T. Alla variabile V si può accedere solo all'interno di:
Region V when (B) do S;
S è la sezione critica fatta da una o più istruzioni che accedono ad una variabile globale
condivisa che è V, cioè vengono eseguite le istruzioni S sulla variabile V solo se la condizione
B si verifica.
Message Passing
Il message passing è una tecnica di sincronizzazione che si utilizza quando i processi non
sono risiedenti sulla stessa macchina e quindi non hanno memoria globale condivisa. La
comunicazione avviene mediante l’instaurazione di una connessione client-server mediante
socket che sono canali di comunicazione che prevedono un server ed un client.
Un server crea una socket mediante la chiamata di sistema:
s = socket (dominio, tipo, protocollo)
Che restituisce un identificatore di socket al processo.
Un client crea una socket mediante la chiamata socket e tenta di connetterlo al socket di un
server utilizzando la system call:
connect (cs, server_socket_addr, server_socket_addrlen)
La comunicazione tra un client e un server è implementata mediante le chiamate read e write
o send (invio) e receive (ricezione) che possono essere bloccanti o non bloccanti.
- Send bloccante, il processo mittente si blocca finchè il ricevente non riceve il messaggio.
questa metodologia di message passing prende il nome di message passing sincrono .
- Send non bloccante, il processo mittente continua la sua esecuzione subito dopo aver
inviato il messaggio, questa metodologia prende il nome di message passing asincrono
- Receive bloccante, il processo riceve il messaggio inviato dal mittente e prosegue la sua
esecuzione
- Receive non bloccante, se non ci sono messaggi in arrivo il processo si blocca in attesa
di messaggi o continua l'esecuzione rinunciando a ricevere il messaggio
Tipicamente viene utilizzata una send non bloccante.
49
Appunti di Sistemi Operativi Teoria
50
Appunti di Sistemi Operativi Teoria
Problemi di sincronizzazione
Esistono una serie di problemi classici nella programmazione concorrente che vengono
utilizzati per dimostrata l'efficienza di determinate teorie od algoritmi e forniscono una base
comune per poter effettuare dei paragoni.
Produttore e consumatore
Questo problema è anche noto come problema del buffer a capienza limitata.
Esso si compone di un numero non specificato di produttori e consumatori, e di un insieme
finito di buffer, ciascuno dei quali è in grado di contenere un elemento di informazione. Un
buffer è pieno quando un produttore scrive un nuovo elemento al suo interno. Un buffer è
vuoto quando un consumatore estrae un elemento contenuto in esso.
Un processo produttore produce un elemento di informazione alla volta e lo inserisce in un
buffer vuoto. Un processo consumatore estrae l'informazione, un elemento alla volta, da
un buffer pieno.
Una soluzione al problema produttori-consumatori deve soddisfare queste condizioni:
1. un produttore non deve sovrascrivere un buffer pieno
2. un consumatore non deve consumare un buffer vuoto
3. i produttori e i consumatori devono accedere ai buffer in maniera mutuamente esclusiva
Sono stati pensati molti approcci software per la risoluzione di questo problema, ne
elenchiamo alcune:
Produttore-Consumatore mediante Sezioni Critiche
Produttore-Consumatore mediante Semafori
Produttore-Consumatore mediante Regioni Critiche
Produttore-Consumatore mediante Message Passing
Produttore-Consumatore mediante Monitor
Produttore consumatore mediante Variabili di condizione
51
Appunti di Sistemi Operativi Teoria
52
Appunti di Sistemi Operativi Teoria
53
Appunti di Sistemi Operativi Teoria
SPIEGAZIONE
Il buffer è un record condiviso costituito da un array[n-1] elementi, count, in, out.
Ovviamente il produttore deve caricare un nuovo oggetto nell’array Pool condiviso, IN è il
puntatore alla prossima posizione da inserire encrementando sempre in aritmetica
modulare, COUNT è il contatore di elementi.
N.B. : è un costrutto ad alto livello che rende trasparente al programmatore tutto quello che
c’è dietro poiché la condizione B (COUNT < N) viene valutata e se vero si eseguono le istruzioni
S. Se COUNT >= N il processo si mette in attesa sulla Regione in una coda.
Il consumatore verifica la disponibilità di prelievo di un elemento (COUNT > 0) se è vero
esegue S che è il blocco di istruzioni per prelevare un elemento.
54
Appunti di Sistemi Operativi Teoria
La soluzione non usa alcuna variabile condivisa. Il processo Pi, ovvero il processo produttore,
ha una variabile chiamata buffer, mentre il processo Pj, il processo consumatore, ha una
variabile chiamata area_messaggio.
Il processo produttore produce, inserisce nel buffer e invia il contenuto del buffer in un
messaggio al consumatore. Il consumatore riceve il messaggio in area_messaggio e da lì lo
consuma. La chiamata di sistema send blocca il processo produttore finchè il messaggio non
viene consegnato al consumatore, e la chiamata di sistema receive blocca il consumatore
finchè il messaggio non gli viene inviato.
Questa soluzione è restrittiva in quanto consente di avere un unico processo produttore
ed un unico processo consumatore. L’implementazione N-N non può avvenire poichè non
possono condividere il buffer poichè non vi è memoria condivisa e quindi risulta sconosciuto
N (cioè il numero di produttori o consumatori), questo problema potrebbe essere risolto
inviandolo insieme al messaggio oppure inviandolo a parte, ma scegliendo questa seconda
soluzione non possiamo sapere se arriva prima N o il pacchetto o viceversa e quindi la
sincronizzazione non avviene in modo corretto.
55
Appunti di Sistemi Operativi Teoria
56
Appunti di Sistemi Operativi Teoria
SPIEGAZIONE
Abbiamo la parte iniziale che è Monitor chiamato Buffer. E’ caratterizzato da variabili
condivise e procedure ( buffer(), riempi(), svuota() )
Produttore, non fa altro che invocare la Riempi sul buffer, dopo aver prodotto un
dato. Non effettua nessun controllo poiché tutti i controlli avvengono nel monitor.
Consumatore, esegue svuota passando un dato e successivamente lo consuma.
Riempi, per prima cosa controlla se non ci sono posizioni libere (contatore == N), se
è vero effettua una wait se nonpieno, cioè inserisce un altro processo in coda ai
processi che attendono che Contatore < N (ovvero che non sia pieno). Se la condizione
non è verificata, quindi vi è una posizione libera è possibile caricare un dato nel buffer
nella posizione indicata da nextin(buffer[nextin]=item). Successivamente riaggiorna
nextin (nextin=(nextin + 1)%N) in aritmetica modulare poiché il buffer è circolare.
Ora è possibile incrementare contatore indicando ua posizione libera in meno
(contatore++) e segnalare ad un eventuale consumatore la presenza di un dato nel
buffer per far risvegliare un processo in attesa (nonvuoto.signal)
Svuota, effettua un controllo per verificare se il buffer è vuoto (contatore == 0), se la
condizione è verificata non è possibile prelevare e il processo va aggiunto alla lista dei
processi che attendono che il contatore > 0 (nonvuoto.wait). Se invece vi sono
elementi nel buffer, viene prelevato il dato nella posizione indicata da nextout
(item=buffer[nextout]), viene aggiornato nextout in aritmetica modulare
(nextout=(nextout+1) % n), viene decrementata la variabile globale contatore
(contatore--)che indica il consumo di un dato nel buffer e quindi il liberarsi di una
posizione e ovviamente la signal su nonpieno per notificare ai processi in attesa che
è ora possibile immettere un dato.
57
Appunti di Sistemi Operativi Teoria
SPIEGAZIONE
Il produttore attende fin quando il buffer non è vuoto. Dopodiche produce, aggiorna il
puntatore con aritmetica modulare del buffer circolare, incrementa il numero di elementi
prodotti (contatore) e segnala al consumatore che il buffer è pieno (pieno.signal()).
Il consumatore attende fin quando il buffer non è pieno. Dopodichè consuma l’elemento nel
buffer, aggiorna il puntatore con aritmetica modulare del buffer circolare, decrementa il
numero di elementi nel buffer e segnala al produttore che il buffer è vuoto.
58
Appunti di Sistemi Operativi Teoria
Lettore – Scrittore
Abbiamo due processi che devono effettuare due operazioni differenti. Uno deve Leggere e
l’altro deve Scrivere su un insieme di dati condivisi tra più processi concorrenti. Più processi
lettori possono leggere tranquillamente e non vi è sezione critica in quanto i dati non
vengono alterati. Il problema si pone quando vi è almeno uno scrittore che accede ai dati.
Se un processo scrittore sta aggiornando i dati nessun altro processo può aver accessom
neanche in lettura.
Dato che entrambi i processi vogliono accedere concorrentemente ai dati bisogna
determinare chi può accedere per primo:
1. Se accede prima il lettore legge il dato che intendeva leggere e poi lo scrittore aggiorna.
2. Se accede prima lo scrittore, modifica il dato e successivamente il lettore legge il dato
modificato.
Tutto dipende dalla politic ache viene adottata. Vi è un bivio, nel senso che bisogna
determinare a quale processo dare priorità da qui vi sono due soluzioni.
Variabili condivise:
Semaforo mutex := 1
Semaforo scrittura := 1
Numlettori := 0
Processo Lettore
59
Appunti di Sistemi Operativi Teoria
60
Appunti di Sistemi Operativi Teoria
E’ stata progettata per evitare il possibile effetto lato da parte degli scrittori
Processo Scrittore
Stessa struttura del processo lettore precedente. Ovviamente, per il processo lettore era stato
introdotto Mutex per gestire l’accesso a numlettori, ora avendo più scrittori c’è bisogno di
un secondo mutex: mutex1.
Ovviamente la priorità è data solo in concorrenza, poichè se vengono schedulati prima i lettori
gli viene concessa la possibilità di andare in sezione critica, ugual cosa per gli scrittori.
Se arrivano processi in modo confuse, sul semaforo Lettura possiamo avere un misto di
processi, più precisamente il problema si pone su sem_signal(lettura), poichè potremmo
risvegliare solo scrittori ecc..
Per evitare questo problema inseriamo Z, però vi è ridondanza di informazione poichè su Z
vi sono solo lettori che si trovano su lettura. Effettuando la sem_signal(z) risvegliamo
sicuramente un lettore, effettuando la sem_signal(lettura) potremmo risvegliare uno
scrittore in questo caso diamo allo scheduler il compito della scelta
61
Appunti di Sistemi Operativi Teoria
I Soluzione
SPIEGAZIONE
Il filosofo fa una sem_wait(chopstick[i])(bacchetta
sinistra) e una sem_wait(chopstick[(i+1)%5]) (array
circolare), prenota le 2 bacchette, mangia e le rilascia
effettuando 2 signal.
N.B. : questa soluzione non esclude lo stallo poiché
se due filosofi adiacenti prenotano la bacchetta alla
loro sinistra, si bloccheranno.
62
Appunti di Sistemi Operativi Teoria
II Soluzione
SPIEGAZIONE
Un filosofo può prendere le bacchette solo se entrambe sono disponibili. La verifica della
disponibilità delle bacchette deve essere fatta in modo atomico. Prima di poter mangiare
ogni filosofo verifica le bacchette con prendi_forchetta(i) che è una funzione che verifica se
può prenderle, fondamentalmente dichiara di volerlo fare e attende il suo turno. Per
dichiarare questa volontà settiamo una variabile di stato AFFAMATO, dopodichè verifica le
bacchette.
Void controlla_se_può_mangiare(), Se il mio settato è AFFAMATO ed entrambi i
filosofi alla mia destra e sinistra non stanno mangiando (bacchette disponibili) allora
63
Appunti di Sistemi Operativi Teoria
III Soluzione
Si dichiarano gli stati in cui il filosofo può trovarsi con un array di 5 elementi. Si introducono
5 variabili di condizione dove il filosofo i-esimo può ritardare se stesso quando ha fame ma
non riesce ad ottenere le bacchette.
SPIEGAZIONE
L’implementazione di posa usa la stessa procedura dei semafori senza il semaforo contatore
in quanto nonostante una coda il semaforo binario non permette di controllare il numero di
processi in attesa.
Prende(), dichiara l’intenzione del filosofo di mangiare, verifica le bacchette, dopodichè se lo
stato è != MANGIA (non ho potuto mangiare), il filosofo si mette in attesa sulla variabile di
condizione AUTO (variabile di condizione associate a AUTO e STATO[i])
Verifica(), controlla se il filosofo di destra e quello di sinistra stanno mangiando, se non è
vero e lo stato del filosofo fosse AFFAMATO, setta lo stato a Mangia e risveglia un filosofo
64
Appunti di Sistemi Operativi Teoria
Barbiere addormentato
Nella sala di un barbiere vi sono n sedie in attesa ed una sedia del barbiere. Egli dovrà
essere risvegliato all’arrivo del cliente altrimenti resta in attesa. Questa particolarità ci
permette di dire che dovrà essere associato ad un semaforo:=0 su cui il barbiere effettuerà
una wait e si bloccherà.
Quando arriva un cliente effettua una signal per risvegliare il barbiere addormentato. Il fatto
di avere n Sedie ci indica un semaforo contatore:=N per cui quando un vliente entra effettua
una wait su questa risorsa (cioè si siede). Qualora le n Sedie fossero tutte occupate il cliente
va via.
SPIEGAZIONE
Barbiere
Effettua una wait(clienti), se clienti era posto ad 1 significa che vi era un barbiere sulla
sedia, decrementa i clienti in attesa e fa sedere il cliente sulla sedia, il tutto in mutua
65
Appunti di Sistemi Operativi Teoria
esclusione. Se vi fossero più clienti seduti sulle sedie quello che si siederà dal barbiere sarà
quello che viene schedulato e che risveglia il barbiere poiché non vi è una coda associata al
semaforo contatore.
Segue la signal(barbiere) che rappresenta il momento in cui il barbiere attende che il cliente
si sia seduto e inizia a lavorare. La signal(mutex) viene fatta alla fine.
Cliente. Controlla se tutte le sedie sono occupate, per farlo accede in mutua esclusione. Se
in_attesa<N, lo incrementa e mediante signal(clienti) risveglia il barbiere che si era bloccato
su clienti. Solo dopo consentito il prosieguo dei processi, effettua la signal(mutex). Dopo con
la wait(barbieri) attende che il barbiere lo risvegli.
N.B. : in questa soluzione l’ordine è imposto dal programmatore indipendentemente dalla
politica di scheduling
SPIEGAZIONE
Barbiere
Il processo barbiere si ferma fintanto che non vi sono clienti. All’arrivo di un cliente
decrementa la coda dei clienti in attesa e sveglia il barbiere che procede al taglio.
Clienti
Se vi è posto per sedersi il cliente si siede quindi incrementa la coda, notifica la sua presenza
e acquisisce il barbiere per procedere al taglio. Altrimenti va via.
66
Appunti di Sistemi Operativi Teoria
Deadlock
Lo stallo è una situazione di blocco tra processi, si verifica quando uno o più processi
richiedono delle risorse che sono già in possesso da altri processi che le detengono senza
farne un rilascio immediato.
67
Appunti di Sistemi Operativi Teoria
Evitare il deadlock
Per evitare lo stallo si può:
Non iniziare un processo in via ripetitiva non allocandogli alcuna risorsa (rifiuto di
allocazione)
Ammettere il possesso e attesa, cioè ammettere che il processo possa richiedere ed
ottenere risorse, ma ogni volta che richiede una risorsa sarà necessario eseguire un
algoritmo, definito come Algoritmo del Banchiere.
Rifiuto di allocazione
I processi sono simili a clienti che chiedono prestiti (risorse) ad una banca, e la banca non
concede prestiti se non è in grado di soddisfare completamente le richieste di almeno un
cliente.
In ogni istante lo stato del sistema è definito da:
Risorse totali (Ri)
Risorse richieste dal processo K (Ck)
Risorse allocate al processo K (Ak)
Risorse richieste dal processo k per completare l’esecuzione (Nk = Ck – Ak)
Risorse disponibili nel sistema (V)
68
Appunti di Sistemi Operativi Teoria
poi, viene controllato se qualche altro processo può soddisfare questa condizione e
così via.
Prevenire il deadlock
Per prevenire il deadlock bisogna negare le 4 condizioni:
1. Negando la mutua esclusione, cioè consentire a più processi di entrare in sezione
critica, quindi virtualizzando le risorse.
2. Negando il possesso e l’attesa, cioè consentire che le risorse vengano allocate al
processo tutte inizialmente per poi essere rilasciate alla fine.
3. Negando la nessuna prelazione, cioè consentire alla CPU di prelazionare
forzatamente una risorsa allocata ad un processo per allocarla ad un altro.
4. Negando l’attesa circolare, cioè ordinando numericamente i processi in modo da
non far creare cicli.
Ignorare il deadlock
Si sposta il problema all’amministratore del sistema, che accortosi dello stallo applica la
politica da lui reputata più opportuna oppure lo ignora e prosegue il suo lavoro.
69
Appunti di Sistemi Operativi Teoria
Memoria
Un calcolatore possiede una gerarchia di memoria. Lo scopo di una gerarchia di memoria è
quello di dare l'illusione di una memoria veloce e grande.
La CPU fa riferimento alla memoria più veloce, la cache, quando deve accedere a
un'istruzione o a un dato. Se l'istruzione o il dato non è disponibile in cache, viene prelevato
dal livello successivo della gerarchia di memoria, che potrebbe essere una cache più lenta
oppure la memoria RAM. Se l'istruzione o il dato non è disponibile nemmeno al livello
successivo della gerarchia, viene prelevato da un livello inferiore e così via. Per mantenere in
memoria un elevato numero di processi, il kernel può decidere di mantenere in memoria
anche solo una parte dello spazio di indirizzamento di ogni processo. A tal fine si utilizza la
parte della gerarchia della memoria chiamata memoria virtuale che si compone della
memoria RAM e dell'hard disk. Le parti dello spazio di indirizzamento di un processo non
presenti in memoria vengono caricate dal disco quando necessario(swapping).
70
Appunti di Sistemi Operativi Teoria
Swapping
Lo swapping viene effettuato tra la memoria e l’area di swap del disco per avere un
avvicendamento tra le parti dei processi in memoria central e quelle sul disco. La memoria
central è suddivisa come segue:
Modulo residente del S.O., tipicamente si trova nella parte bassa della RAM
ROM, il S.O. si trova nella ROM e il programma utente si triva nella RAM
Utilizzare la ROM per avere solo I driver dei dispositive, in tal caso la RAM è divisa in
due parti (modulo residente del so e programmi utente)
Binding
Un'operazione molto importante nella gestione della memoria è il binding, ovvero il processo
tramite cui si associano gli indirizzi di memoria alle entità di un programma.
Questa operazione può essere effettuata in 3 momenti diversi:
1. durante la compilazione (binding statico)
2. durante il caricamento (binding statico)
3. durante l'esecuzione (binding dinamico)
71
Appunti di Sistemi Operativi Teoria
Partizionamento
Dato che l’obiettivo principale nei sistemi è massimizzare il livello di
multiprogrammazione(avere quanti più processi possibili gestiti in memoria centrale) si è
pensato a varie tecniche per gestire la memoria che è pur sempre finita per quanto grande
possa essere.
Partizionamento fisso
Il modo più semplice per realizzare la multiprogrammazione è quello di dividere la memoria
in n partizioni fisse di diversa dimensione. Ogni partizione deve contenere esattamente un
processo, quindi il grado di multiprogrammazione è limitato al numero di partizioni. Dal
momento che le partizioni sono fisse, tutto lo spazio di una partizione non usato dal processo
viene sprecato.
In questo tipo di multiprogrammazione vengono utilizzati due approcci per le code di processi
che portano all'allocazione dei processi nelle varie partizioni della memoria:
A code separate
A coda unica
72
Appunti di Sistemi Operativi Teoria
di cercare in tutta la coda in ingresso ogni volta che si libera una partizione, e scegliere il job
più grande che può entrarci.
Partizionamento variabile
Per superare alcune delle difficoltà che si incontrano nel partizionamento fisso, si può
utilizzare il partizionamento variabile. Questo genere di multiprogrammazione è quello
utilizzato nei moderni SO.
Con il partizionamento variabile quando un processo è caricato in memoria centrale, gli viene
allocata tanta memoria quanta ne richiede lasciando piccolo spazi tra un allocazione ed un
altra inutilizzabili (frammentazione esterna). Per risolvere il problema della frammentazione
esterna si può utilizzare la tecnica della “compattazione della memoria” cioè si compattano
tutti gli spazi liberi in memoria creando un unico grande spazio riutilizzabile. Questa tecnica
comporta overhead.
Per gestire lo spazio libero e occupato in memoria vi sono alcuni metodi:
Gestione con Bitmap
Gestione con liste a puntatori
73
Appunti di Sistemi Operativi Teoria
dimensione dell'area di memoria (buco) sono maggiori delle dimensioni richieste dal
processo; questo algoritmo divide l'area di memoria in due parti, parte viene assegnata
al processo, la restante viene reinserita nella free list.
Next-fit: questo algoritmo è un caso particolare di First-fit. La differenza è che in
questo algoritmo si assegna al processo il primo buco abbastanza grande da
contenerlo a partire dal punto in cui era terminata la ricerca precedente.
Best-fit: questo algoritmo assegna al processo il più piccolo buco capace di
contenerlo. Si può facilmente intuire che bisogna ricercare il buco scorrendo
completamente la free list.
Worst-fit: questo algoritmo assegna il buco più grande al processo. Anche qui si deve
esaminare l'intera lista. Lo scopo di questo algoritmo è quello di produrre buchi più
grandi, cercando di evitare la frammentazione esterna.
Buddy system
Un allocatore buddy divide e ricombina i blocchi di memoria in modo predeterminato durante
l'allocazione e la deallocazione. I blocchi creati dividendo un blocco sono chiamati blocchi
buddy. I blocchi buddy liberi vengono uniti per ricreare il blocco da cui erano stati creati.
Questa operazione prende il nome di fusione. Secondo questo sistema, i blocchi liberi contigui
che non sono buddy non sono fusi.
In un buddy system binario, i blocchi di memoria disponibile hanno dimensione 2K, con
L K U, dove:
- 2^L - blocco allocato di dimensione più piccola
- 2^U - blocco allocato di dimensione più grande; generalmente 2U è la dimensione
dell'intera memoria disponibile per l'allocazione
Inizialmente l'intero spazio disponibile è trattato come un singolo blocco buddy di dimensione
2^U. Quando deve essere allocata un'area di dimensione S:
- se 2^U-1 < S 2^U allora viene allocato l'intero blocco di dimensione 2U; altrimenti il
blocco viene diviso in due parti, ciascuna di dimensione 2^U-1
- se 2^U-2 < S 2^U-1 allora uno dei due blocchi è allocato per intero; altrimenti uno dei
due blocchi è diviso in due metà di dimensione 2^U-2 questo processo viene ripetuto fino
ad ottenere il più piccolo blocco buddy di dimensione S
- Per evitare che i blocchi buddy diventino di dimensione troppo piccola viene inserito un
limite minimo, che una volta raggiunto non consente di dividere a metà l'i-esimo blocco
buddy.
Complessità
log (2^U/2^L) = (log(2^U) – log(2^L)) = U - L
74
Appunti di Sistemi Operativi Teoria
Il logaritmo è in base 2
75
Appunti di Sistemi Operativi Teoria
Paginazione
Nella paginazione ogni processo viene paginato cioè diviso in parti di dimensione fissata
chiamate pagine, la cui dimensione viene definita dall'architettura del sistema. La memoria
può memorizzare un numero intero di pagine e viene partizionata in aree o blocchi di
memoria, dette frame, che hanno la stessa dimensione di una pagina. Quindi ogni area di
memoria (frame) può contenere una sola pagina. Dato che ogni processo è diviso in varie
pagine, gli viene associate una tabella dove sono racchiuse tutte le informazioni sul processo
e sulle sue pagine, questa tabella è detta: tabella delle pagine. Le pagine non sono tutte
caricate in memoria ma vengono caricate in memoria solo nel momento in cui vi si fa
richiesta, questo tipo di paginazione è detta: Paginazione su richiesta.
76
Appunti di Sistemi Operativi Teoria
77
Appunti di Sistemi Operativi Teoria
tabella delle pagine invertite. Quì posso ricostruire il frame che aggiunto all'offset normale
ricostruisce l'indirizzo fisico reale. Nel caso di collisione si usa il concatenamento che
reindirizza a un nuovo elemento della tabella. Utilizzando questa struttura quindi abbiamo
solo una entry nella tavola di hash e nella tabella delle pagine invertita per ogni pagina di
memoria reale invece che una per ogni pagina virtuale. La gestione delle collisione però
provoca overhead.
78
Appunti di Sistemi Operativi Teoria
Lo spazio di indirizzamento fisico dipende dal numero di linee del bus indirizzi. Se M è il
numero di linee del bus indirizzi allora lo spazio di indirizzamento fisico sarà 2^M.
Traduzione indirizzi
La traduzione da indirizzo logico ad indirizzo fisico la effettua l’MMU che riceve dalla CPU
una coppia di valori (pi, bi), dove pi è il numero di pagina e bi il numero di byte (o
offset).L’MMU utilizza il numero di pagina pi per indicizzare la tabella delle pagine del
processo, ottiene il numero del frame della pagina allocata a pi e calcola l'indirizzo di memoria
effettivo secondo l'equazione:
Indirizzo fisico di (pi, bi) = indirizzo di avvio del frame allocato a pi * dimensione della pagina
+ numero dei byte di bi nella pagina pi
Esempio:
Consideriamo un processo P in un sistema che usa una pagina di dimensione 1 KB. I byte
in una pagina sono, quindi, numerati da 0 a 1023.
Il processo P ha indirizzo di avvio 0 e dimensione 5500 byte. Dunque avrà 6 pagine numerate
da 0 a 5. Le pagine 0, 1, 2, 3 e 4 avranno 1024 byte, per un totale di 5120 byte; mentre la
pagina 5 avrà solo 380 byte, i restanti sono sprecati (causano frammentazione interna).
79
Appunti di Sistemi Operativi Teoria
Se un dato sample ha indirizzo 5248, ovvero 5 x 1024 + 128, vuol dire che si trova nella
pagina 5; la MMU vede il suo indirizzo come la coppia (5, 128).
Traduzione
indirizzo di memoria effettivo di (5, 128)
= indirizzo di avvio del frame allocato a 5 + numero dei byte, cioè "frame #8 + 128"
= 8 x 1024 + 128
= 8320
La dimensione di una pagina è potenza di 2, così il calcolo dell'indirizzo effettivo è eseguito
tramite concatenazione di bit, che è molto più veloce dell'addizione appena vista. Preso un
indirizzo logico costituito da ll bit, alcuni di questi bit (quelli più significativi) saranno usati
per rappresentare il numero di pagina dell'indirizzo logico, gli altri bit (quelli meno
significativi) saranno usati per rappresentare lo scostamento (in byte) in quella pagina.
In pratica:
- gli np bit più significativi danno la pagina pi
- gli nb bit meno significativi danno lo scostamento bi
Sia la pagina pi allocata nel frame qi, poiché hanno la stessa dimensione, allora l'indirizzo
fisico (qi, bi) sarà costituito da:
- gli nf bit più significativi danno il frame qi
- gli nb bit meno significativi danno lo scostamento bi
Il numero del frame viene preso dalla tabella delle pagine e corrispondeva agli nf bit. A questi
bit vengono poi concatenati gli altri nb bit che rappresentano lo scostamento.
La MMU ottiene questo indirizzo semplicemente concatenando qi e bi per ottenere un numero
di bit lp.
Page fault
Supponiamo che la CPU voglia usare un certo dato o una certa istruzione.
La MMU, nell'effettuare la traduzione degli indirizzi verifica, facendo uso della tabella delle
pagine, se quella pagina è presente o meno in memoria (fa riferimento al campo bit di validità).
Se la pagina non è presente, si genera un page fault e il gestore della memoria virtuale carica
la pagina in memoria e aggiorna la tabella delle pagine.
Infatti alcune pagine virtuali non possono avere corrispondenza in memoria fisica, il bit di
validità è usato proprio per indicare se la pagina è presente o meno in memoria. Si ha page
fault quando un processo tenta di usare una pagina non mappata, cioè non presente in
memoria. Il controllo del bit di validità è effettuato al passo 2: la MMU controlla il bit di
validità della tabella delle pagine; se è 0 vuol dire che la pagina non è presenta in memoria,
dunque la MMU genera un interrupt chiamato page fault, che è un interrupt di programma.
80
Appunti di Sistemi Operativi Teoria
A causa dell'interrupt viene invocato il gestore della memoria virtuale che carica la pagina in
memoria e aggiorna la tabella delle pagine di quel processo. In pratica, MMU e gestore della
memoria virtuale interagiscono per decidere quando una pagina di un processo deve essere
caricata in memoria.
Quando un processo vuole usare una pagina non presente in memoria e ci sono frame liberi
in memoria, il gestore della memoria virtuale carica la pagina dallo spazio di swap (sul disco)
in memoria. Questa operazione prende il nome di page-in.
Quando il gestore della memoria virtuale decide di rimuovere una pagina dalla memoria,
copia la pagina nello spazio di swap (sul disco) Questa operazione prende il nome di page-
out. Quando un processo vuole usare una pagina non presente in memoria e non ci sono
frame liberi in memoria è necessario ricorrere alla sostituzione delle pagine. La
sostituzione di pagina diventa necessaria quando si verifica un page fault e non ci sono frame
liberi in memoria.
Questa operazione viene svolta dal gestore della memoria virtuale che:
- seleziona una delle pagine attualmente in memoria utilizzando un algoritmo di
sostituzione delle pagine
- modifica il campo bit di validità di questa pagina, settandolo a 0 (non presente);
facendo questa operazione, la pagina diventa dirty
- effettua un'operazione di page-out per copiare la pagina sul disco in quanto la pagina
è dirty
- effettua un'operazione di page-in per caricare in memoria, nel frame appena liberato,
la pagina richiesta dal processo
- modifica il campo bit di validità della pagina appena caricata, settandolo ad 1
(presente)
N.B. Durante queste operazioni, lo stato del processo viene impostato a blocked; solo dopo
l'operazione di page-in viene ripristinata l'esecuzione del processo. Nel frattempo, la CPU è
assegnata ad altri processi.
Le tabelle delle pagine vengono tenute in memoria per le loro grandi dimensioni, ma ciò può
penalizzare fortemente le prestazioni, infatti una singola istruzione può fare riferimento a più
indirizzi. Se a questo aggiungiamo il fatto che i programmi tendono a fare la maggior parte
dei riferimenti a un piccolo numero di pagine, allora si può concludere che solo una piccola
parte degli elementi nella tabella delle pagine viene letta con maggior frequenza.
Una possibile soluzione per aumentare le prestazioni è quello di usare il TLB (Tanslation
Look-aside buffer).
81
Appunti di Sistemi Operativi Teoria
82
Appunti di Sistemi Operativi Teoria
Per accedere in memoria viene consumato del tempo, per calcolare il tempo di accesso
effettivo in memoria (EAT) si utilizzano varie formule.
EAT
Prima formula senza TLB
PR2 *(Ttlb+Tmem)+(PR1-PR2)x(Ttlb+2Tmem)+
+ (1-PR1) x (Ttlb+Tmem+Tpf+Ttlb+2Tmem)
83
Appunti di Sistemi Operativi Teoria
secondaria. Accedo quindi al TLB con insuccesso, poi alla memoria con insuccesso genero il
pagefault, carico la pagine nel TLB ed effettuo due accessi alla memoria. Ecco spiegato Ttlb
+ Tmem + Tpf + Ttlb + 2Tmem
Formula complete
PR2 * (TTLB + TMEM), Cerco la pagina nel tlb, quindi se la pagina è presente nel TLB
avrò un tempo di ricerca pari TTLB + un tempo di accesso alla memoria dopo aver
creato l indirizzo fisico per farci riferimento.
Ora bisogna sommare la probabilità in cui la pagina non venga trovata nel TLB ma sia
presente in RAM
(PR1-PR2) * (TTLB+ 2TMEM),PR1-PR2 è proprio la probabilità di non trovare la
pagina nel TLB ma è in memoria centrale, quindi bisogna accedere al TLB con
insuccesso (TTLB) e poi due volte in memoria centrale (2TMEM) una per creare
l’indirizzo fisico ed una per farci riferimento.
Ora bisogna gestire il caso in cui non ci sia in memoria centrale:
+ (1-PR1)* %D_0 *(TTLB+TMEM+TPF+TTLB+2TMEM)+,(1-PR1) Indica la probabilità
di non trovare la pagina in RAM e quindi verrà generato un page fault , pensando che
la pagina abbia il bit di modifica settato a 0 (%D_0) e quindi non necessita di un page
out, quindi si accede al TLB con insuccesso (TTLB) successivamente si prova in
memoria (TMEM) con insuccesso, viene generato un page fault (TPF), viene caricata
la pagina nel TLB con tempo TTLB e poi 2 volte in memoria uno per creare l indirizzo
fisico ed una per farci riferimento.
+(1-PR1)* %D_1 * (TTLB+TMEM+TPF+TSWAP+TTLB+2TMEM), Se invece la pagina
ha il bit di modifica a 1 la pagina necessita di un page out e quindi bisogna aggiungere
il tempo di swap sul disco.
84
Appunti di Sistemi Operativi Teoria
Oppure in memoria non vi sono frame liberi, in questo caso bisogna cercare una
pagina “vittima” da scaricare sul disco. Per determinare quale sia la pagina vittima da
selezionare vengono utilizzati degli algoritmi di sostituzione delle pagine.
Ovviamente l’obiettivo sarebbe utilizzare una strategia che in caso di page fault ne restituisca
il minimo possibile, ma per fare ciò si deve avere un informazione globale sugli accessi in
memoria centrale. Per fare ciò si introduce il concetto di Page Address Stream (stringa di
riferimenti) cioè la frequenza di riferimenti alle pagine durante l’esecuzione di un processo.
Quindi valutare I page fault che una strategia produce significa valutare i page fault che
produce su una data stringa di riferimenti. La stringa di riferimenti tiene conto del numero
di pagina e non dell’indirizzo intero quindi se facciamo riferimento a più indirizzi all’interno
della stessa pagina, questi non causano page fault.
Algoritmi di sostituzione
Sostituzione Ottimale
Algoritmo FIFO
85
Appunti di Sistemi Operativi Teoria
per questo motivo viene raramente utilizzato nella sua forma pura. E’ facile da implementare
poichè è un buffer circolare ma risulta non efficiente in quanto non considera l’uso delle
pagine ma solo il momento del primo caricamento.
Questa politica soffre però di un anomalia detta: anomalia di Belady. L’idea è sempre quella
di cercare di minimizzare quanto più possibile i page-fault ,quindi un idea sarebbe
aumentare i frame a disposizione in memoria.
Ma dal grafico si evince che anche
aumentando i frame in memoria ad
un certo punto i PF aumentano invece
di diminuire. Per questo motivo il
gestore della memoria non può
utilizzare l’algoritmo FIFO per sostituire le pagine.
Algoritmo LRU
La politica di sostituzione delle pagine LRU, a ogni page fault, sostituisce la pagina
utilizzata meno di recente con la pagina richiesta. In pratica, viene scaricata la pagina
usata meno di recente. Questa politica è realizzabile ma non è conveniente, poiché per
implementarla completamente, è necessario mantenere liste concatenate di tutte le
pagine in memoria, con la pagina usata più di recente in testa alla lista; la difficoltà sta nel
fatto che la lista va aggiornata ad ogni riferimento alla memoria. Quindi, eseguire ad ogni
istruzione operazioni di ricerca e manipolazione in una lista concatenate è molto costoso in
termini di tempo.
L’implementazione è possibile tramite due approcci:
Contatori, secondo tale implementazione la tabella delle pagine è mantenuta come
lista concatenate avente un campo aggiuntivo per ogni entry della tabella che contiene
il contatore cioè il tempo in cui è avvenuto l ultimo utilizzo della pagina a cui esso
corrisponde. Per implementare tale strategia va copiato il contenuto dle registro clock
ad ogni riferimento di pagina nel campo dell’ora di utilizzo della tabella relative alla
pagina specifica. Quando si rende necessario un cambiamento di pagina va ricercato
il contatore con il valore minore e quindi va sostituita la pagina associate ad esso.
Stack, che contiene I numeri di pagine associate alla tebella delle pagine e viene
gestito tramite liste concatenate a doppio puntatore. Se avviene un riferimento ad una
pagina esso corrisponde al caricamento al top dello stack la pagina, questo per
mantenere sempre al top la pagina che utilizziamo piu frequentemente e questo
procedimento produce una modifica di 6 puntatori (puntatore al top, il puntatore
che il top usa per puntare al fondo, I due puntatori che il top usa per puntare
all’elemento successive e infine I due puntatori che vengono aggiornati nel momento
86
Appunti di Sistemi Operativi Teoria
in cui la pagina viene estratta dal top dello stack). Accanto a questo overhead di
modifica dei puntatori vi è però un vantaggio cioè non bisogna effettuare nessuna
ricerca della pagina vittima poichè essa è quella che si trova al fondo dello stack
puntata dall’elemento di coda e quindi la complessità di tempo impiegato per
cancellare un element dal fondo è pari a O(1).
Bit di riferimento, che è presente per ogni pagina della tabella delle pagine. Viene
inizialmente posto a 0 e viene poi posto ad 1 quando la pagina viene riferita. Il controllo
sul bit di riferimento tiene conto del valore cioè se esso è 0 la pagina è sia vecchia
che non utilizzata di recente e quindi viene sostituita, se invece il valore è 1 il bit
viene posto a 0 e la pagina viene accodata alla lista come se fosse appena caricata in
memoria. In alternativa a questo utilizzo del bit di riferimento vie è l algoritmo Clock.
Algoritmo Clock
L’algoritmo di clock utilizza una lancetta per puntare ai frame che contengono le pagine
caricate. L’algoritmo cerca la pagina che non è stata utilizzata recentemente e che ha,
quindi, il bit di riferimento settato a 0 e la ricerca avviene in senso orario.
Il bit di riferimento di una pagina è impostato a 1 quando:
- la pagina è caricata per la prima volta in un frame in memoria
- quando la pagina caricata nel frame viene utilizzata
Quando si verificare un page fault, si effettua una scansione della lista e si sostituisce il
frame che ha il bit di riferimento posto a 0. Nell'algoritmo di clock a una lancetta, una
esecuzione è composta da due passi su ogni pagina. Nel primo passo, il gestore della memoria
virtuale semplicemente resetta il bit di riferimento della pagina puntata dal puntatore, nel
secondo passo cerca tutte la prima pagina che ha il bit di riferimento settato a 0, la quale poi
diventa la pagina vittima e la lancetta si sposta di una posizione indicando che la prossima
scansione deve partire dalla posizione da essa puntata(successive alla sostituzione
precedente).
87
Appunti di Sistemi Operativi Teoria
Strategie alternative
Esistono strategie alternative di sostituzione della pagina vittima, in particolare è possibile
mantenere un contatore del numero di riferimenti che sono stati effettuati ad ogni pagina. In
tal caso si parla di “frequenza” e quindi possiamo avere:
LFU (Last Frequently Used), secondo la quale la pagina con il minor numero di
riferimenti alla pagina è quella che risulta essere la pagina vittima
MFU (Most Frequently Used), che si basa sulla congettura che una pagina con il
contatore minore molto probabilmente è stata caricata da poco in memoria centrale e
quindi non ha avuto tempo di essere utilizzata. Invece una pagina con il contatore
maggiore, cioè utilizzata più volte, ha più probabilità di non essere piu utilizzata in
futuro.
88
Appunti di Sistemi Operativi Teoria
Windows
Windows utilizza un allocazione dei frame ai processi Variabile in ambito Locale, cioè la
pagina vittima viene cercata solo tra I frame allocate al processo.
Quindi ad ogni processo inizialmente è allocato un numero fisso di frame, quando avviene
un page fault, esso viene risolto nell’ambito dei frame allocati al processo stesso senza
coinvolgere I frame di altri processi questo per evitare squilibri di allocazione dei frame nei
confronti degli altri processi. Periodicamente la quantità di memoria fisica allocate ai processi
viene Ridefinita in base al comportamento osservato per questo motivo l’allocazione risulta
essere variabile migliorando le prestazioni in quanto ci si adatta alle dinamiche reali dei
processi.
Nello specifico Windows gestisce la memoria utente usando la Paginazione con algoritmo di
sostituzione basato sul Working Set.
89
Appunti di Sistemi Operativi Teoria
Ora se la frequenza va al di sotto del limite inferiore significache vengono generati troppi
pochi page fault e quindi il numero di frame viene diminuito. Viceversa se il numero di page
fault generati è eccessivo il numero di frame allocati al processo aumenta.
90
Appunti di Sistemi Operativi Teoria
Riepilogo
Windows Unix Linux
Allocazione Paginazione Paginazione Paginazione
memoria utente Algoritmo utilizzato: Algoritmo utilizzato: Algoritmo utilizzato:
Working Set Clock
Allocazione Lazy Buddy Buddy System
memoria kernel
Segmentazione
La segmentazione è una tecnica di gestione della memoria che presuppone una divisione
logica da parte del programmatore e rende quindi visibile la memoria ad egli.
Nella segmentazione la memoria è divisa in segmenti di dimensione diversa, ogni segmento
è libero di aumentare la propria dimensione oppure di ridurla, ogni processo ha una propria
tabella dei segmenti all’interno della quale vi sono il campo base e il campo limite che
indicano rispettivamente l’inizio della locazione di memoria allocata al processo e la
lunghezza. Esempi di segmentazione possono essere il main, le funzioni ecc. definite dal
programmatore, per indicarne l’inizio e la fine di questi segmenti vengono utilizzati dei TAG
dopodichè il compilatore vede quei tag come delimitatori dei segmenti di un processo. Uno
dei vantaggi rispetto alla paginazione è proprio la flessibilità dei segmenti infatti se una
struttura dati presente in un segmento si espande il kernel aumenta la dimensione del
segmento senza intaccare gli altri segmenti, cosa che non accade nella paginazione essendo
tutte le pagine una a ridosso dell’altra e quindi un eventuale modifica ad un area di memoria
potrebbe far cambiare molti indirizzi. Durante la traduzione degli indirizzi avviene una
somma, cioè al campo limite viene sommato la dimensione del dato in byte. Uno svantaggio
è la frammentazione esterna, e quindi di tanto in tanto bisogna compattare la memoria per
ridurla.
91
Appunti di Sistemi Operativi Teoria
Segmentazione paginata
La segmentazione paginata unisce le proprietà della paginazione e quelle della
segmentazione. Ogni processo viene diviso in segmenti, ad ogni segmento viene legata una
tabella delle pagine il cui indirizzo si trova nella tabella dei segmenti in relazione al segmento
esaminato.
Funzionamento
L’indirizzo virtuale ha tre campi: numero del segmento, numero della pagina e l offset.
Prelevo il primo campo (numero del segmento) e lo utilizzo come puntatore nella
tabella dei segmenti.
Consultando il campo puntato dal numero del segmento ottengo il puntatore
all’indirizzo di partenza della pagina relativa a quel segmento
Sommando il secondo campo dell indirizzo virtuale (num di pagina) e il puntatore
precedente ottengo l’indice per la tabella delle pagine
Consulto il campo nella tabella delle pagine ed ottengo il frame
Aggiungo al frame il terzo campo dell indirizzo virtuale(offset) ed ottengo l indirizzo
fisico.
92
Appunti di Sistemi Operativi Teoria
93
Appunti di Sistemi Operativi Teoria
numero di frame liberi va al di sotto della soglia più bassa esegue un loop finchè non libera
qualche frame andando ad esaminare il frame alla fine della lista inattiva se il suo bit di
riferimento è 1, resetta il bit e sposta il frame in cima alla lista, altrimenti liber ail frame.
Linux usa un allocatore Buddy system per l’allocazione dei frame ai processi.
Durante la traduzione degli indirizzi il campo PD index viene utilizzato per localizzare una
tabella delle pagine. Il campo PT index è usato per selezionare un entry a 32 bit della tabella
delle pagine (PTE) che contiene un indirizzo a 20bit del frame della pagina. Il campo byte
index è concatenato con il suo indirizzo per ottenere l’indirizzo fisico.
94
Appunti di Sistemi Operativi Teoria
FileSystem
Il filesystem è un modulo del sistema operativo che si occupa della gestione dei file
Gli obiettivi sono:
- Gestione dati e requisiti utente
- Garantire che i dati nel file siano mantenuti validi, quando più processi vogliono accedere
a un file viene garantita la memoria centrale
- Ottimizzare le prestazioni, quindi alto throughput globale e basso tempo di risposta
- Fornire supporto di I/O perchè la gestione delle periferiche avviene tramite file quindi le
periferiche stesse vengono considerate dei file
- Minimizzare la possibilità di dati persi o distrutti, quando si effettuano le operazioni di
ricompattamento o datacleaning bisogna fare in modo che non si perdano dati
- Fornire un insieme di procedure di interfaccia all'i/o standardizzate, il sistema di gestione dei
file tratta un file indipendentemente dal dispositivo sul quale esso risiede per questo usa
sempre le stesse interfacce
Analizzando l'architettura del filesystem. Partendo dal basso verso l'alto troviamo:
Driver del dispositivo, comunicano direttamente con le periferiche
File System Base o I/O Fisico, si occupa dei blocchi di dati scambiati con un
dispositivo. Organizza i blocchi su disco e il buffer in memoria centrale. Esso non
capisce il contenuto dei dati e nemmeno la struttura
Supervisore di I/O base, in base al file capisce qual è il dispositivo ad esso associato.
Si occupa anche della schedulazione del disco. Il supervisore raggruppa le richieste
degli utenti e le schedula in modo opportuno e solo dopo le passa all'I/O fisico che le
organizza in blocchi. Gli utenti però non vedono i file in questa organizzazione a
blocchi, ecco perchè è necessaria una organizzazione logica.
I/O logico abilita utenti o applicazione ad accedere ai record.
Metodo di accesso, fornisce un'interfaccia tra le applicazioni e il filesystem quindi
anche ai dispositivi
95
Appunti di Sistemi Operativi Teoria
Per raggiungere gli obiettivi in maniera efficace il filesystem contiene anche una parte detta
IOCS (input output control system) che si occupa dell’implementazione delle operazioni sui
file. Organizza inoltre i dati di un file in un dispositivo di I/O relativamente al tipo di file. Per
comunicare con i dispositivi di I/O si utilizzano diversi metodi:
I/O programmato, tutto il lavoro è gestito dalla CPU che non può eseguire nessun
altra operazione mentre gestisce un operazione di I/O.
Interrupt I/O, la CPU esegue un operazione di I/O e viene chiamata in causa
mediante l’abilitazione di un interrupt e avvia l ISR (interrupt service routine) per
gestirlo. Il vantaggio è che la CPU non rimane in attesa attiva ma può dedicarsi ad
altro, lo svantaggio è che la procedura di gestione dell’interrupt ha un costo per il
salvataggio e il ripristino del contesto.
I/O basato su DMA, la gestione dell’ I/O è demandata al DMA(direct memory access)
che si occupa di trasferire dati da e verso la memoria centrale rendendo quindi la CPU
indipendente. Funziona cosi:
o La CPU comunica al DMA l’operazione da compiere sul dispositivo.
o Pone sul bus degli indirizzi l indirizzo del dispositivo coinvolto
o Pone sul bus dati la posizione iniziale in memoria da cui leggere/scrivere e il
numero di parole coinvolte.
A questo punto la CPU è libera. Quando il trasferimento in memoria è terminato il
DMA invia un interrupt alla CPU che però non è un vero e proprio interrupt normale
poiché non richiede ISR quindi non necessita di salvataggio e ripristino di contesto
ma la CPU si ferma solo per un ciclo di bus (cycle stealing) avendo un leggero
rallentamento (DMA breakpoint). Sono tre i momenti in cui possono avvenire:
o Prima della fase di fetch
o Dopo la fase di decode
o Dopo la fase di execute
La configurazione del DMA puo avvenire:
A bus singolo, DMA separato
Il DMA utilizza un I/O programmato per scambiare i dati tra memoria e vari dispositivi.
Abbiamo un unico bus per tutti i moduli, il che la rende poco efficiente poiché onerosa
dato che tutti usano lo stesso canale.
A bus singolo, DMA e I/O integrati
96
Appunti di Sistemi Operativi Teoria
Il DMA e i dispositivi sono integrati e quindi ci sarebbe bisogno di un DMA per ogni
dispositivo e in piu viene sempre usato un singolo bus di comunicazione.
A doppio bus
Vi sono due bus uno per il sistema ed uno per i dispositivi di I/O che vengono
raggruppati per classi. I dispositivi comunicano col DMA tramite il proprio bus ed il
DMA comunica con la memoria o con la CPU tramite il bus di sistema.
Tipi di file
Un file System contiene ed organizza diversi tipi di file che possono essere raggruppati in:
File strutturati, cioè una collezione di record che a loro volta sono una
collezione di campi che contengono dati.
File orientati allo stream di byte, cioè viene visto come una sequenza di byte.
N.B.: I record sono unità logiche di accesso ad un file, mentre i blocchi sono le unità di
memorizzazione dell'I/O con la memoria secondaria.
Attributi di un file
Gli attributi che generalmente caratterizzano un file sono:
Nome
Identificatore
Tipo
Dimensione
97
Appunti di Sistemi Operativi Teoria
Sequenziale
Nel file sequenziale l’organizzazione avviene su nastro o su un disco.
Su nastro i record vengono posti uno di seguito all’altro mantenendo
una coda ma per poter modificare un record in coda con accesso
sequenziale bisogna scansionare tutti i record che lo precedono, per
questo motivo si utilizza un LOG FILE cioè un file di appoggio dove
mettere i nuovi record prima di inserirli nella giusta posizione nel file sequenziale che viene
denominato FILE MASTER. L’ordine è basato su un campo CHIAVE.
98
Appunti di Sistemi Operativi Teoria
99
Appunti di Sistemi Operativi Teoria
Allocazione di File
Dobbiamo innanzitutto scegliere il metodo di organizzazione del blocco ovvero come fare
entrare i record in un blocco.
E' uguale al caso del blocco fisso con la differenza che il record può avere dimensione
variabile. C'è comunque frammentazione interna sempre per il fatto che il record viene
inserito solo se può entrare tutto quanto.
100
Appunti di Sistemi Operativi Teoria
Allocazione concatenata
101
Appunti di Sistemi Operativi Teoria
dei blocchi del file. Per cancellare un file, la lista di blocchi del file viene semplicemente
aggiunta alla free list.
Ad esempio, nella figura:
il file alpha è costituito da due blocchi, il numero 3 e il numero 2;
il file beta è costituito da tre blocchi, il numero 4, seguito dal 5, seguito dal 7 - la free
list è di tre blocchi, l'1, il 6 e l'8.
VANTAGGI:
Il vantaggio principale di questa allocazione è che è sufficiente memorizzare in ogni
elemento della directory solamente l'indirizzo su disco del primo blocco, mentre la
parte rimanente si può trovare a partire da esso. Questo porta anche ad una lettura
sequenziale semplice da effettuare.
SVANTAGGI:
L'accesso diretto è estremamente lento, perché per arrivare al blocco n occorre
necessariamente aver letto gli n-1 blocchi che lo precedono.
Un ulteriore svantaggio riguarda lo spazio richiesto per i puntatori. La soluzione
più comune a questo problema consiste nel riunire un certo numero di blocchi
continui in gruppi (cluster) e nell'assegnare i gruppi di blocchi anziché i singoli blocchi.
Un altro problema riguarda l'affidabilità. Se si danneggiasse il campo metadati di
un blocco, cioè se si danneggiasse il puntatore, i dati successivi al blocco danneggiato
potrebbero essere persi. Ci sono delle soluzioni a questo problema, come l'uso di liste
doppiamente concatenate, che però sono onerose da implementare.
Una variante importante del metodo di assegnazione concatenata consiste nell'uso della
tabella di assegnazione dei file, una tabella di questo tipo, tenuta in memoria, si chiama FAT
(File Allocation Table). La FAT ha un elemento per ogni blocco del disco. Per un blocco allocato
a un file, il corrispondente elemento della FAT contiene l'indirizzo del blocco successivo. In
questo modo il blocco e il suo elemento nella FAT insieme formano una coppia che contiene
la stessa informazione contenuta nel blocco nel classico schema dell'allocazione concatenata.
102
Appunti di Sistemi Operativi Teoria
L'elemento di una directory relativo a un file contiene l'indirizzo del primo blocco sul disco.
L'elemento della FAT corrispondente a questo blocco contiene l'indirizzo del secondo blocco
e così via. L'elemento della FAT corrispondente all'ultimo blocco contiene un valore speciale
di fine file.
VANTAGGI:
L'uso della FAT fornisce maggiore affidabilità rispetto alla classica allocazione
concatenata poiché il danneggiamento di un blocco contenente i dati del file comporta
danni limitati.
SVANTAGGI:
In questa allocazione, il danneggiamento di un blocco usato per memorizzare la
FAT risulta disastroso. Inoltre, le prestazioni sono peggiori poiché è necessario
accedere alla FAT per ottenere l'indirizzo del blocco successivo.
Allocazione indicizzata
103
Appunti di Sistemi Operativi Teoria
ORGANIZZAZIONE IBRIDA
Alcuni file system implementano un'organizzazione ibrida
della FMT che include alcune delle caratteristiche
dell'allocazione classica e dell'allocazione indicizzata
multilivello. I primi elementi nella FMT, ad esempio n
elementi, puntano a blocchi dati come nell'allocazione
indicizzata. Gli altri elementi puntano a blocchi indice. Il
vantaggio di questa organizzazione è che piccoli file
continuano a essere accessibili in maniera efficiente,
poiché la FMT non utilizza i blocchi indice. I file di medie o grandi dimensioni soffrono di un
parziale degrado delle prestazioni di accesso a causa dei livelli di indirizzamento
Questo ricorda l’organizzazione dei file in Unix.
104
Appunti di Sistemi Operativi Teoria
105
Appunti di Sistemi Operativi Teoria
Superblocco
La radice di un file system è chiamata superblock
Una parte del disco, solitamente quella iniziale, viene utilizzata per il codice di avvio del SO.
Dopo lo spazio che viene lasciato per questo codice, si colloca il superblocco. Esso si può
considerare come una tabella riassuntiva delle caratteristiche e dello stato del file system.
Le informazioni che contiene consentono di sapere:
dimensione dei blocchi - posizione degli i-node
numero di i-node
blocchi liberi
blocchi allocati
Organizzazione logica
All’inizio della progettazione dei sistemi operativi vi era un solo livello e quindi essendo un
solo utente non vi era la necessità delle directory. Con l’avvento della possibilità di utilizzo
dello stesso pc da piu utenti è nata l’esigenza delle directory. Con la seconda versione dei
sistemi operativi si introduce un secondo livello di profondità cioè esistevano varie directory
ognuna dedicata ad un utente (struttura a due livelli).
106
Appunti di Sistemi Operativi Teoria
esistono molti file con lo stesso nome. Tuttavia l'utilizzo delle UD ha uno svantaggio:
impedisce agli utenti di condividere i loro file con altri utenti. Per raggiungere tale
obiettivo sono necessarie istruzioni speciali che permettono a degli utenti di accedere
ai file di altri utenti; per fare ciò occorre verificare i permessi dei file (che si trovano nel
campo Prot_Info).
Struttura ad albero
Un approccio più potente e flessibile è l'approccio gerarchico o ad albero delle directory.
In questa struttura, il file system fornisce all'utente una directory chiamata root che contiene
la directory home per ciascun utente, ovvero una directory che, solitamente, ha lo stesso
nome del nome utente. Un utente può creare file oppure può creare directory all'interno della
sua home, con la possibilità di
organizzazione le proprie informazioni in una struttura basata su diversi livelli di
sottodirectory.
Ad ogni istante, si dice che un utente si trova in una specifica directory, chiamata
directory corrente. Quando l'utente vuole aprire un file, il file viene cercato in questa
directory. Quando l'utente effettua il login, il SO permette all'utente di operare solo
nella sua directory home.
Il nome dato a uno specifico file può non essere unico nel file system, per cui un utente o un
processo utilizza un path per identificarlo in maniera univoca. Il path è il percorso di tutte
le sottodirectory in cui si trova il file. Nel path ogni riferimento è un directory tranne l'ultima
che è, appunto, il file stesso.I path per localizzare un file a partire dalla directory corrente
sono detti path relativi, che sono spesso corti e convenienti da usare; tuttavia, possono
essere fonte di confusione poiché un file può avere diversi path relativi quando vi si accede a
partire da diverse directory correnti.Il path assoluto di un file parte dalla directory root
dell'albero delle directory del file system. I file con lo stesso nome creati in directory differenti
differiscono nei rispettivi path assoluti.
107
Appunti di Sistemi Operativi Teoria
Struttura a grafi
In un albero di directory, ogni file eccetto la
directory root ha esattamente una directory
genitore. Una struttura del genere separa
totalmente i file di utenti differenti; in pratica
non ammette la condivisione di file e
directory tra più utenti. Questo problema
può essere risolto organizzando le directory
in una struttura a grafo aciclico. Un grafo
aciclico permette di avere sottodirectory e file
condivisi. Il fatto che il file sia condiviso non
significa che ci siano due copie del file.
In questa struttura, un file può avere molte directory genitore, per cui un file condiviso può
essere puntato dalle directory di tutti gli utenti che hanno accesso ad esso. Le strutture a
grafo aciclico possono essere implementate in vari modi.
LINK
Un metodo molto diffuso prevede la creazione di un nuovo elemento di directory, chiamato
link (o collegamento). Un link è un puntatore ad un altro file o directory, in pratica è una
connessione diretta tra due file esistenti. L'operazione di cancellazione risulta complessa
quando la struttura è un grafo poiché un file può avere molti genitori. Un file è cancellato
quando ha un solo genitore; altrimenti viene semplicemente reso inaccessibile dalla directory
che si vuole cancellare. Per semplificare l'operazione di cancellazione, il file system associa
ad ogni file un contatore di link: il contatore è impostato a 1 quando viene creato il file, viene
incrementato di 1 quando un link punta al file, viene decrementato di 1 quando viene
eseguita una cancellazione. Il file viene cancellato definitivamente quando il contatore dei
link diventa 0.
108
Appunti di Sistemi Operativi Teoria
causa un failure. Per ovviare a questi problemi bisognerebbe fare un DUMP (backup
completo) dei dati. Abbiamo due tipi di dump:
Dump fisico
Dump logico
Dump fisico
Il dump fisico inizia dal blocco 0 del disco e scrive tutti i blocchi in ordine. Il problema sta
nel fatto che copia anche i blocchi non utilizzati. Se si saltassero questi bisognerebbe
ricordare quanti se ne è saltati e gli indici non sarebbero più consecutivi, quindi il kappesimo
di uno non sarà più il kappesimo dell'altro. Un altro problema riguarda i blocchi danneggiati,
questi vengono rimappati dal controllore del disco e nascosti al so in modo che non li usi, in
questo caso il dump fisico non ha problemi. Se invece sono visibili al so, e quindi anche al
dump, bisogna evitare di leggerli perevitare errori di lettura durante il dump
Dump logico
Comincia in corrispondenza di una directory specifica e effettua il dump di tutti i file e le
directory che sono cambiate rispetto a una data. Quindi in un dump logico il nastro di dump
ha una serie di file e directory identificati che permettono il recupero selezionato
JSF
Un file system durante l'esecuzione mantiene in memoria una parte dei file dati e dei
metadati, in particolare mantiene in memoria i file control block, le file map table e le
free list. Quando l'esecuzione di un fle system viene terminata dall'utente del sistema, il file
system copia tutti i dati ei metadati dalla memoria RAM sul disco, in modo che la copia sul
disco sia completa e consistente. Tuttavia, quando si verifica una mancanza di corrente
elettrica o quando il sistema viene spento all'improvviso, il file system non ha l'opportunità
di copiare i file dati e i metadati sul disco. Questo spegnimento è detto spegnimento sporco
e causa una perdita dei dati dei file e dei metadati contenuti in memoria. Tradizionalmente,
i file system utilizzavano delle tecniche di ripristino per proteggersi contro la perdita di dati
e metadati poiché erano molto semplici da implementare. Per questo motivo, si creavano
backup periodici e i file erano ripristinati a partire dalle copie di backup nel momento in cui
si verificavano dei malfunzionamenti. La creazione delle copie di backup comportava un
piccolo overhead durante il normale funzionamento del sistema. Tuttavia, quando si verifica
un malfunzionamento, l'overhead per la correzione delle inconsistenza era elevato ed, inoltre,
il sistema non era disponibile durante il ripristino. Un file system moderno utilizza tecniche
di fault tolerance in modo da poter riprendere l'esecuzione velocemente dopo uno
spegnimento improvviso. Un journaling file system implementa la fault tolerance
mantenendo un journal, un diario giornaliero, dove vengono salvate le azioni che il file system
109
Appunti di Sistemi Operativi Teoria
si accinge ad eseguire prima di eseguirle effettivamente. Quando l'esecuzione del file system
viene ripristinata dopo uno spegnimento improvviso, il file system consulta il journal per
identificare le azioni non ancora eseguite e le esegue, garantendo in questo modo la
correttezza dei dati dei file e dei metadati. L'uso di tecniche di fault tolerance genera un
elevato overhead. Per questo motivo il JFS offre diverse modalità journaling. Un
amministratore di sistema può scegliere una modalità journaling da adattare al tipo di
affidabilità necessaria nell'ambiente di elaborazione.
FSV
Gli utenti richiedono requisiti differenti a un file system, come convenienza, alta affidabilità,
risposte veloci e accesso ai file su altri sistemi. Un singolo file system non può fornire tutte
queste caratteristiche, per cui un sistema operativo fornisce un file system virtuale (VFS)
che facilita l'esecuzione simultanea di diversi file system. In questo modo ogni utente può
usare il file system che preferisce. In pratica un file system virtuale è un livello software che
consente a diversi file system di essere in funzione su un computer simultaneamente, in
modo che un utente possa scegliere il file system che è più adatto per le sue applicazioni.
Dischi magnetici
I dischi magnetici sono costituiti da vari piatti, ognuno dei quali contiene tante tracce.
Tutte le tracce uguali posizionate su piatti differenti formano un cilindro. L'elemento di
memorizzazione di un disco magnetico è un oggetto circolare chiamato piatto, che ruota sul
suo asse ed è ricoperto da un materiale magnetico. Ogni piatto memorizza i byte lungo delle
tracce circolari sulla sua superficie. Ogni traccia è divisa in settori ed il numero di settori
può variare a seconda delle tracce. I dischi moderni sono divisi in zone con più settori e zone
con meno settori, ma grazie alla virtualizzazione, il SO vede tutte le zone come se avessero lo
stesso numero di settori, dunque le richieste vengono fatte su quella base.
La testina è capace di leggere e scrivere sulla superficie del piatto. Essa è capace di
110
Appunti di Sistemi Operativi Teoria
111
Appunti di Sistemi Operativi Teoria
Raid
Gli utenti necessitano di dischi con maggiore capienza, accesso ai dati più veloce, tassi di
trasferimento maggiori e maggiore affidabilità. Se a queste esigenze si aggiungere il fatto che
col passare degli anni la forbice tra le prestazioni della CPU e degli hard disk tende ad
aumentare sempre di più, ecco spiegati i motivi che hanno portato allo sviluppo della
tecnologia RAID (redundant array of inexpensive disks). Esistono diverse configurazioni RAID
che utilizzano differenti tecniche di ridondanza e organizzazione.
Queste tecniche sono chiamate livelli RAID e, ad oggi, vanno da 0 a 6. Esistono inoltre due
configurazioni ibride basate sui livelli 0 e 1, che insieme al livello 5 risultano le configurazioni
più usate.
Nelle configurazioni dei RAID gioca un ruolo fondamentale anche il calcolo del MTTF: Mean
Time To Failure, cioè il tempo impiegato da un disco per guastarsi e quindi fallire.
Raid 0
Nel RAID 0 i dati vengono distribuiti su più dischi con la tecnica dello
striping: i dati sono divisi equamente tra due o più dischi con nessuna
informazione di parità o ridondanza.
VANTAGGI:
Garantisce tassi di trasferimento elevati grazie agli accessi contemporanei ai vari dischi.
SVANTAGGI:
Ha una scarsa affidabilità. I dati diventano inaccessibili anche nel caso di un singolo disco
spento. Inoltre la mancanza di ridondanza causa la perdita dei dati nel caso di
malfunzionamento di un disco.
112
Appunti di Sistemi Operativi Teoria
Raid 1
Nel RAID 1 viene creata una copia esatta di tutti i dati su due o più
dischi. Questa tecnica prende il nome di disk mirroring. Se un dato
viene aggiornato da un processo, una copia di questo dato viene copiata
su ogni disco. Ciò aumenta l'affidabilità rispetto al sistema a disco
singolo. Infatti, se si verifica un malfunzionamento ad uno dei dischi, un
dato può essere recuperato dagli altri dischi.
VANTAGGI:
Maggiore affidabilità visto che vengono create tante copie dei dati quanti sono i dischi.
Migliori prestazioni in lettura, visto che il dato viene letto dal disco a cui si può
accedere prima.
SVANTAGGI:
Viene prodotto molto overhead visto che ad ogni aggiornamento di un dato, devono
essere aggiornati anche le sue copie presenti sugli altri dischi.
Il sistema vede un unico disco, ma con una capienza pari a quella del disco fisico più
piccolo.
Raid 2
Nel RAID 2 viene utilizzata la tecnica
del bit striping: si memorizza ogni
bit (invece che i blocchi) di dati
ridondanti su un disco differente.
Inoltre vengono salvati su altri
dischi, i codici per la correzione degli
errori. Solitamente si usa il codice di
Hamming visto che esso è in grado di
correggere errori su singoli bit e rilevare errori doppi. In pratica, una parte dei dischi viene
usata per salvare i dati, mentre la restante parte viene usata per salvare solo le informazioni
per la correzione degli errori.
113
Appunti di Sistemi Operativi Teoria
VANTAGGI:
Affidabilità molto alta.
Velocità di lettura molto alta: visto che i dati sono spezzettati su molti dischi, la
possibilità di leggere in parallelo i vari dischi, aumenta notevolmente la velocità di
lettura.
SVANTAGGI:
Il numero di dischi utilizzati da questo sistema può essere molto alto.
Raid 3
Il RAID 3 non è altro che una semplificazione del
RAID 2. Infatti la differenza sostanziale tra i due
livelli è che nel RAID 3 viene utilizzato un solo
disco per il salvataggio dei codici per la
correzione. Questo è possibile sostituendo il codice
di Hamming con un nuovo metodo, il bit di parità.
Un sistema RAID 3 usa una divisione al livello di
byte. Ogni operazione di I/O richiede di utilizzare
tutti i dischi.
MTTF = (MTTFdisco)^2 \ (Numerodischi*(Numerodischi – 1) * MTTR)
Raid 4
Il RAID 4 è analogo al RAID 3 fatta eccezione per il
fatto che usa una divisione a livello di blocchi con un
disco dedicato alla memorizzazione dei codici di
parità. La differenza sostanziale sta proprio nel
modo in cui
i dati vengono divisi: nel RAID 3 sono divisi a livello
di byte, nel RAID 4 sono divisi al livello di blocchi
VANTAGGI:
Possono essere effettuate più operazioni di I/O contemporaneamente se le operazioni
114
Appunti di Sistemi Operativi Teoria
Raid 5
Il RAID 5 è analogo al RAID 4 fatta eccezione per il fatto
che i codici di parità sono distribuiti su tutti i dischi.
in questo modo, se l'operazione di scrittura interessa un
singolo blocco, il sistema ha comunque la possibilità di
effettuare altre operazioni di scrittura in parallelo.
MTTF = (MTTFdisco)^2 \
(Numerodischi*(Numerodischi – 1) * MTTR)
VANTAGGI:
Possibilità di effettuare scritture e in parallelo se queste richiedono un solo blocco.
Un solo disco viene utilizzato per memorizzare i codici per la correzione degli errori.
SVANTAGGI:
Possibilità di eseguire una sola operazione di I/O in ogni istante se vengono richiesti
più blocchi. Difficile da implementare.
Raid 6
Un RAID 6 usa una divisione a livello di
blocchi con i dati di parità distribuiti due
volte tra tutti i dischi.
Risulta più ridondante del RAID 5 a causa
dell'esistenza di un disco in più rispetto al RAID
5.
115
Appunti di Sistemi Operativi Teoria
Raid 0 + 1
Effettua prima lo striping, cioè alterna i dati su
diversi dischi, come nel RAID 0; poi copia gli stessi
dati su un altro disco, come nel RAID 1.
Raid 1 + 0
Copia prima gli stessi dati su un altro disco, come
nel RAID 1; poi alterna i dati su dischi diversi.
116
Appunti di Sistemi Operativi Teoria
Scan
Questa politica è nota come algoritmo dell'ascensore. Muove le testine del disco da un estremo
all'altro del piatto, servendo tutte le richieste che ci sono lungo la sua strada
indipendentemente dal loro ordine di arrivo; una volta raggiunta l'ultima traccia, cioè l'altra
estremità del piatto, la direzione di movimento viene invertita e le nuove richieste vengono
servite nella scansione inversa
Look
E’ una variante della politica Scan che inverte la direzione delle testine del disco quando non
ci sono più richieste di I/O nella direzione corrente.
C-Scan
Questa politica esegue la scansione come nello scheduling SCAN. Tuttavia, non esegue mai
la scansione inversa, quindi la scansione viene ridotta ad un'unica direzione. Invece di
procedere in direzione opposta, questa politica sposta le testine nella posizione di partenza
sul piatto e inizia un'altra scansione
C-Look
Questa politica muove le testine solo finchè ci sono richieste da eseguire prima di iniziare
una nuova scansione.
117
Appunti di Sistemi Operativi Teoria
Sicurezza e protezione
I SO adottano misure di sicurezza e protezione per evitare che un utente non autorizzato
possa utilizzare, illegalmente, le risorse di un sistema o interferire con esse in qualsiasi modo.
Le misure di sicurezza riguardano le minacce provenienti dall'esterno di un sistema.
Le misure di protezione si occupano delle minacce interne.
Minacce: Trojan,virus,worm
I trojan sono genericamente software malevoli (malware) nascosti all'interno di programmi
apparentemente utili, e che dunque l'utente esegue volontariamente. Il tipo di software
malevolo che verrà silenziosamente eseguito in seguito all'esecuzione del file da parte
118
Appunti di Sistemi Operativi Teoria
dell'utente può essere sia un virus che un qualunque tipo di minaccia informatica poiché
permette al cracker che ha infettato il PC di risalire all'indirizzo IP della vittima. L'intruso può
quindi controllare il PC infettato da remoto, può "spiarlo", può negargli servizi, ecc.
I virus sono software, appartenenti alla categoria dei malware, in grado, una volta eseguiti,
di infettare dei file in modo da riprodursi facendo copie di sé stessi, generalmente senza farsi
rilevare dall'utente.Un virus è composto da un insieme molto piccolo di istruzioni, che viene
aggiunto alla istruzioni di un programma eseguibile presente sulla macchina. È solitamente
composto da un numero molto ridotto di istruzioni in modo da rendersi il più possibile
invisibile. Un virus tipicamente configura una backdoor, o porte di servizio, che consentono
all'intruso di superare in parte o in tutto le procedure di sicurezza attivate in un sistema
informatico. Con l'attivazione di una backdoor un utente esterno può prendere il controllo
remoto della macchina senza l'autorizzazione del proprietario.
Un worm è una particolare categoria di malware in grado di autoreplicarsi. È simile ad un
virus, ma a differenza di questo non necessita di legarsi ad altri eseguibili per diffondersi.
Sicurezza in Windows
La sicurezza in Windows si basa sull’uso di Identificativi di sicurezza (SID) che viene dato
ad un host, un utente o ad un dominio. Ogni processo ha un token di accesso che identifica
il suo contest di sicurezza. Un token di accesso è generato quando un utente effettua il login
e contine il SID per l’account utente e un SID per il group account che vengono utilizzati dal
security reference monitor per decider se il processo che ha il token di accesso può eseguire
certe operazioni su di un oggetto. Un utente può creare piu token di accesso mediante la
funzione LogonUser.
Cifratura
La cifratura è l'applicazione di una trasformazione algoritmica ai dati in modo tale da
proteggere i dati stessi. La crittografia è quella branca della crittologia che si occupa di
tecniche di cifratura. L'obiettivo è quello di prendere un messaggio o un file, chiamato
messaggio in chiaro, e crittarlo in messaggio cifrato in modo tale che soltanto un utente,
che conosce come ripristinare la forma originale del dato, lo può utilizzare. Questa
caratteristica aiuta a mantenere la riservatezza del dato. La segretezza del dato dipende dai
parametri dell'algoritmo, cioè dalle chiavi di cifratura: l'efficacia della cifratura dipende dal
fatto che un intruso possa determinare la chiave di cifratura attraverso tentativi ed errori. In
pratica, il messaggio cifrato è ottenuto usando un algoritmo di crittazione (noto), un
messaggio in chiaro ed una chiave di cifratura (non nota).
La cifratura si divide in:
cifratura simmetrica
119
Appunti di Sistemi Operativi Teoria
cifratura asimmetrica
Cifratura Simmetrica
Nella tradizionale cifratura simmetrica, viene utilizzata un'unica chiave sia per codificare, sia
per decodificare i messaggi. Delle due informazioni (la chiave e l'algoritmo) necessarie a chi
deve inviare il messaggio, la chiave è quindi identica a quella necessaria a chi deve riceverlo,
mentre l'algoritmo è facilmente reversibile in quello di decifrazione. Per concordare una
chiave con il proprio interlocutore, c'è bisogno di mettersi preventivamente in contatto con
lui incontrandolo di persona, telefonandogli, scrivendogli una lettera, mandandogli un
messaggio o in qualsiasi altro modo. In qualsiasi caso, esiste il pericolo che la chiave venga
intercettata durante il tragitto, compromettendo quindi l'intero sistema comunicativo.
Cifratura Asimmetrica
La crittografia a chiave pubblica permette invece a due (o più) persone di comunicare in tutta
riservatezza senza usare la stessa chiave e anche se non si sono mai incontrate
precedentemente. Per utilizzare questo tipo di crittografia, è necessario creare una coppia di
chiavi. Quando vengono generate le due chiavi sono equivalenti (una delle due
indifferentemente può essere resa pubblica). La proprietà fondamentale delle due chiavi è
che un messaggio cifrato usando una delle due chiavi può essere decifrato soltanto usando
l'altra chiave e viceversa. Ciò significa sostanzialmente che le due chiavi funzionano "insieme"
pur non essendo possibile dall'una desumere l'altra.
Esempio di cifratura
Immaginiamo che A debba inviare un messaggio a B. Per fare ciò il procedimento è il
seguente:
1. A e B si accordano su un certo algoritmo crittografico
2. B spedisce a A la sua chiave pubblica
3. A codifica il suo messaggio usando la chiave pubblica di B
4. A spedisce a B il messaggio cosi codificato
5. B decodifica il messaggio di A usando la propria chiave privata
120
Appunti di Sistemi Operativi Teoria
Tecniche di cifratura
Cifratura a sostituzione
La tecnica di cifratura più semplice è la classica sostituzione del blocco, o anche detta
cifratura per sostituzione, che sostituisce ogni lettera in un testo in chiaro con un'altra lettera
dell'alfabeto. Tale tecnica non maschera molto bene le caratteristiche di un testo in chiaro.
Cifratura a blocchi
La cifratura a blocchi è un'estensione della
cifratura per sostituzione. Esegue una
sostituzione di blocchi di dimensione fissa di
un testo in chiaro con blocchi del testo cifrato
di uguale dimensione. Blocchi identici in un
testo in chiaro producono blocchi identici nel testo cifrato. Questa caratteristica rende
l'approccio vulnerabile a un attacco testo in chiaro conosciuto o testo in chiaro scelto. Per
rendere vita dura agli attacchi, è possibile creare blocchi più grandi.
Cifratura a flusso
Una cifratura a flusso considera che un testo in chiaro, e
la chiave di cifratura siano un flusso di bit. La cifratura è
eseguita usando una trasformazione che prende alcuni bit
del testo in chiaro e un egual numero di bit della chiave di
cifratura. Questa tecnica risulta più veloce della cifratura
a blocchi.
121
Appunti di Sistemi Operativi Teoria
Algoritmi
Des
In crittografia il Data Encryption Standard (DES) è un algoritmo di cifratura
che si basa su un algoritmo a chiave simmetrica con chiave a 56 bit.
Descrizione
Il DES è l'archetipo della cifratura a blocchi, un algoritmo che prende in
ingresso una stringa di lunghezza fissa di testo in chiaro e la trasforma con
una serie di operazioni complesse in un'altra stringa di testo cifrato della stessa
lunghezza. Presenta la seguente struttura:
Il messaggio è suddiviso in blocchi di 64 bit, ognuno viene gestito
separatamente;
Cifratura e decifrazione procedono attraverso 16 fasi successive (round)
in cui si ripetono le stesse operazioni;
La chiave segreta k è costituita da 64 bit dove 56 vengono utilizzati, mentre i restanti
8 sono di parità.
Dalla chiave k vengono create r sottochiavi k[0]…k[r-1] impiegate una per fase.
Il messaggio viene diviso in due metà S e D (sinistra e destra) di 32 bit ciascuna. In
ciascuna fase si eseguono due operazioni S D e D f (k[i-1] , D, S), dove f è una
funzione non lineare (funzione di Feistel). Alla fine delle fasi le due metà vengono
nuovamente scambiate e poi concatenate per produrra il crittogramma finale.
La decifrazione consiste nel ripetere il processo invertendo l’ordine delle chiavi.
122
Appunti di Sistemi Operativi Teoria
AES
In crittografia, l'Advanced Encryption Standard (AES) è un algoritmo di cifratura a blocchi.
Opera utilizzando matrici di 4×4 byte chiamate stati.
Come il DES il processo di cifratura e decifrazione opera per fasi, il numero però non è fisso
ma variabile tra 10 e 14 a seconda della lunghezza della chiave del blocco da cifrare. Ogni
fase opera su un blocco di bit e prevede 4 operazioni principali:
1. Ogni byte della matrice è trasformato mediante una S-Box;
2. La matrice così ottenuta è permutata mediante shift ciclici sulle righe
3. Le colonne risultanti vengono opportunamente combinate con un vettore di byte
prestabilito
4. Ogni byte della matrice finale viene posto in XOR con un byte della sottochiave creata
per quella fase.
Come nel DES le sottochiavi vengono create a partire dalla chiave segreta mediante un
opportuno processo di espansione e selezione.
123
Appunti di Sistemi Operativi Teoria
RSA
In crittografia la sigla RSA indica un algoritmo di crittografia asimmetrica, utilizzabile per
cifrare o firmare informazioni.
Funzionamento
Per semplificare il funzionamento immaginiamo che A debba spedire un messaggio segreto
a B. Occorrono i seguenti passaggi:
1. si scelgono a caso due numeri primi, e abbastanza grandi da garantire la sicurezza
dell'algoritmo
2. si calcolano il loro prodotto n = pq
3. si calzola la funzione di Eulero: z = (p - 1) * ( q - 1)
4. si calcola poi un numero e (esponente pubblico), primo con Z e < Z
5. si calcola d (esponente privato) tale che che ed mod z = 1
La chiave pubblica è , mentre la chiave privata è .
Cifratura
Un messaggio viene cifrato attraverso l'operazione trasformandolo nel
messaggio cifrato .
Decifratura
Una volta trasmesso, viene decifrato con .
Ovviamente per le codifiche di stringhe è necessaria una codifica in binario tramite codice
ASCII.
124
Appunti di Sistemi Operativi Teoria
∑𝑛𝑖=1 𝑏𝑖 ∗ 𝑀𝑖
Immaginiamo un mittente che deve comunicare ad un ricevente una stringa binaria
composta da n bit. Dato che la chiave sia per la cifratrura che per la decifratura è pubblica
non vi è nessun garanzia di sicurezza per questo motive dobbiamo distinguere la chiave
pubblica dalla chiave privata. Cioè dobbiamo dar modo di cifrare con la chiave pubblica ma
di decifrare il messaggio solo a chi possiede la chiave private. L’obiettivo è facilitare le
operazioni di cifratura/decifratura ma rendere difficile la rottura. In generale il problema
dello zaino è un problema intrattabile (NP-CO) per tutti coloro che vorrebbero rompere il
Sistema senza avere informazioni sulla chiave, altrimenti il problema diventa di complessità
lineare.
Esempio
A vuole inviare un messaggio cifrato a B.
Passi di B prima della cifratura:
1. Determina la sequenza superincreasing cioè una sequenza scelta in modo tale che
ogni elemento al suo interno sia maggiore della somma dei precedenti, che utilizzerà
come chiave privata
2. Effettua la somma dei pesi della sequenza superincreasing determinando W
3. Sceglie un valore M : M > W
4. Calcola un valore N : N appartenga al range [1 , M) e sia coprimo con M
5. Calcola la chiave pubblica che invierà poi ad A seguendo la formula:
𝑲𝒑 = (𝑾𝒊 ∗ 𝑵) 𝒎𝒐𝒅 𝑴
125
Appunti di Sistemi Operativi Teoria
Cifratura
Passi di A:
1. Riceve la chiave pubblica da B
2. Codifica il messaggio in chiaro di B in binario
3. Divide il messaggio in binario in gruppi pari al numero dei pesi della chiave pubblica
4. Cifra il messaggio in chiaro facendo corrispondere ad ogni 1 il peso corrispondente e
sommandoli.
5. Invia a B il sacco cosi ottenuto
Decifratura
Passi di B:
1. Riceve il sacco generico da A
2. Calcola l’inverso moltiplicativo di N. Cioè
𝒏−𝟏 ∶ 𝒏 ∗ 𝒏−𝟏 ≡ 𝟏 𝑴𝑶𝑫 𝒎
3. Decifra il messaggio seguendo la formula:
𝑺𝒔 = 𝒏−𝟏 ∗ 𝑺𝒉 𝑴𝑶𝑫 𝒎
4. Con ogni singolo risultato ottenuto dalla precedente formula cerca nella sua chiave
privata (sacco superincreasing) il primo valore < risultato i-esimo partendo da
destra ed effettua la sottrazione conservandosi i valori trovati che poi saranno usati
come indici. Il processo si ripete fin quando non si ottiene 0 come risultato.
Esempio:
Supponiamo che A voglia inviare a B la lettera ‘a’.
Passi di B prima della cifratura:
1. Crea la sequenza superincreasing: supponiamo sia questa (2,3,6,13,27,52)
2. Calcola W come sommatoria di tutti i valori della sequenza S: 103
3. Sceglie M = 105
4. Calcola N = 31
5. Calcola la chiave pubblica:
2 * 31 mod 105 = 62
3 * 31 mod 105 = 93
6 * 31 mod 105 = 81
13 * 31 mod 105 = 88
27 * 31 mod 105 = 102
52 * 31 mod 105 = 37
Kiave pubblica : (62,93,81,88,102,37)
126
Appunti di Sistemi Operativi Teoria
Cifratura
Passi di A:
1. Riceve la chiave pubblica
2. Traduce in binario ‘a’ e supponiamo sia : 011000
3. Determina il sacco da inviare a B : (93 + 81) = (174)
4. Invia 174 a B
Decifratura
Passi di B
1. Riceve 174 da A
2. Calcola l’inverso moltiplicativo di 31. N^-1= 61
3. Decifra il messaggio:
174 * 61 mod 105 = 9
4. Cerca il primo valore < 9 nel sacco superincreasing e trova 6,
9–6=3
3–3=0
Valori conservati : 6,3 che saranno gli indici degli 1 per ricostruire il messaggio
in chiaro. Cioè il messaggio originale era: 011000
127
Appunti di Sistemi Operativi Teoria
Dominio di protezione
La matrice di controllo degli accessi, la lista di controllo degli accessi o la capability list
servono a conferire privilegi di accesso agli utenti. Questa soluzione è utile per la segretezza,
obiettivo della sicurezza e della protezione in quanto solo gli utenti autorizzati possono
accedere a un file. Ma da sole non riescono a soddisfare anche il requisito di riservatezza,
che senza altri meccanismi potrebbe essere violato. Per assicurare tale requisito, entra in
gioco il concetto di dominio di protezione. Questo specifica le risorse cui il processo può
128
Appunti di Sistemi Operativi Teoria
accedere. Ogni dominio definisce un insieme di oggetti e tipi di operazioni che si possono
compiere su ciascun oggetto. Si può pensare ad un dominio di protezione come a un
"ambiente di esecuzione" teorico: un processo che agisce all'interno di un dominio di
protezione, può accedere ai file per i quali il dominio di protezione possiede i privilegi di
accesso. In pratica, ad un processo viene consentito di agire all'interno di un dominio di
protezione solo se ha bisogno di accedere ai file per i quali il dominio di protezione ha i
privilegi di accesso. La riservatezza può essere migliorata consentendo a un processo
l'accesso ad alcune risorse solo durante specifiche fasi della sua esecuzione. Per fare ciò, ad
un processo è consentito cambiare il suo dominio di protezione durante l'elaborazione.
Utenti in Unix
In Unix ogni utente ha un ID unico nel sistema. L'amministratore di sistema crea gruppi di
utenti disgiunti e assegna un group_ID unico a ogni gruppo. Le credenziali di un utente sono
composte dalla sua user_ID e il suo group_ID e servono per l'autenticazione dell'utente. Unix
definisce tre classi di utente:
proprietario del file
user group
altri utenti
e fornisce solo tre diritti di accesso:
lettura (r)
scrittura (w)
esecuzione (x).
Per ogni classe di utente viene utilizzato un descrittore di accesso bit-encoded a 3 bit e l'ACL
contiene i descrittori di accesso per le tre classi di utente nella sequenza proprietario, user
group, altri utenti. In questo modo, l'ACL richiede solo 9 bit ed è memorizzata nell'i-node di
un file. L'identità del proprietario del file è memorizzata in un altro campo dell'i-node del file.
Unix cambia il dominio di protezione di un processo sotto due condizioni: quando il processo
effettua una chiamata di sistema e quando è usata la proprietà setuid o setgid.
La chiamata setuid può essere effettuata in due modi.
Un processo può effettuare una chiamata di sistema setuid <id> per cambiare la sua
uid in <id>, e un'altra chiamata di sistema setuid con il suo ID per ritornare al suo
stato originario.
129
Appunti di Sistemi Operativi Teoria
l'uid può essere cambiato implicitamente quando un processo esegue una exec per
eseguire un programma.
130
Appunti di Sistemi Operativi Teoria
131
Appunti di Sistemi Operativi Teoria
- allocazione contigua
- Problema dello zaino
- Funzione F del DES
- Algoritmi di cifratura (chiave di cifratura e decifratura)
- ACL
- Domini di protezione
- Produttore consumatore (message passing, semafori,variabili di condizione)
- DMA
- Logica di controllo del DMA
- DMA break point
- Peterson
- Lettore e scrittore priorità agli scrittori
- Produttore-consumatore quando i processi risiedono su host differenti
- Produttore-consumatore mediante message passing ma soluzione N-N, può avvenire?
- Cos’ è un page fault
- consistenza dati (Swap)
- TLB
- ampiezza TLB
- com'è fatto il TLB (#frame,#pagina,prot_info)
- Dove risiede l’MMU?
- bus unico
- bus fisico e bus logico
- come viene implementato un bus logico? (iocs)
- come può accedere un programmatore ad un bus logico?
- una chiamata per accedere ad una risorsa? (mount)
- sleep
- stato blocked/swapped
- tutti i sistemi operativi possono passare i processi nell'area di swap?
- differenza tra unix / linux (processi/thread)
- crittografia
- come affrontare minacce esterne?
- cos'è un firewall?
- tipi di protezione (sicurezza)
- vi è una rete interna nel calcolatore?
- ipc
- pipe memoria condivisa (fifo)
132
Appunti di Sistemi Operativi Teoria
133