Sei sulla pagina 1di 142

Materiale di

Sistemi Operativi teoria supporto


teoria
alla

Università degli studi di Napoli Parthenope


Appunti di Sistemi Operativi Teoria

Sommario
Introduzione ................................................................................................................................................................ 8

Il Sistema Operativo .................................................................................................................................................... 1

Il Computer .............................................................................................................................................................. 3

Schema generale ................................................................................................................................................. 3

CPU ...................................................................................................................................................................... 3

PSW...................................................................................................................................................................... 3

MMU.................................................................................................................................................................... 4

Cache ................................................................................................................................................................... 5

Interrupt .................................................................................................................................................................. 5

Ciclo di CPU.......................................................................................................................................................... 7

Notazione Polacca-Postfista ............................................................................................................................... 8

Gestione degli interrupt...................................................................................................................................... 8

Processi ........................................................................................................................................................................ 9

PCB ........................................................................................................................................................................... 9

Spazi di indirizzamento ..................................................................................................................................... 10

Contesto di un processo ....................................................................................................................................... 10

ECB ......................................................................................................................................................................... 11

Multitasking ........................................................................................................................................................... 11

Gestione di un processo........................................................................................................................................ 12

Stati di un processo ............................................................................................................................................... 13

Diagramma a 4 stati .......................................................................................................................................... 13

Diagramma a 6 stati .......................................................................................................................................... 14

Casi studio.............................................................................................................................................................. 15

Processi in Unix ................................................................................................................................................. 15

Processi in Linux ................................................................................................................................................ 16

Processi in Windows ......................................................................................................................................... 16

Thread ........................................................................................................................................................................ 17

Thread utente ........................................................................................................................................................ 18

1
Appunti di Sistemi Operativi Teoria

Thread Kernel ........................................................................................................................................................ 18

Thread Ibridi .......................................................................................................................................................... 18

Scheduler ................................................................................................................................................................... 19

Scheduler a breve termine.................................................................................................................................... 19

Efficienza dello scheduler a breve termine ...................................................................................................... 19

Scheduler a medio termine .................................................................................................................................. 20

Scheduler a lungo termine .................................................................................................................................... 20

Politiche di Scheduling .......................................................................................................................................... 20

Politiche non preemptive ................................................................................................................................. 20

Politiche preemptive ......................................................................................................................................... 22

Con priorità o senza priorità ............................................................................................................................. 25

Statiche e dinamiche.................................................................................. Errore. Il segnalibro non è definito.

Scheduling a code multiple ................................................................................................................................... 25

Scheduling a code multiple con feedback ............................................................................................................ 25

Scheduling a lotteria.............................................................................................................................................. 26

Scheduling garantito ............................................................................................................................................. 26

Scheduling real-time ............................................................................................................................................. 26

Criterio di schedulabilità ................................................................................................................................... 27

Earlier deadline first .............................................................................................................................................. 27

Scheduling in Unix ................................................................................................................................................. 28

Prelazionabilità del Kernel .................................................................................................................................... 28

Sincronizzazione tra processi .................................................................................................................................... 29

Sezione critica.................................................................................................................................................... 29

Condizioni per una corretta sincronizzazione .................................................................................................. 30

Race condition ................................................................................................................................................... 30

Condizioni di Bernstein ..................................................................................................................................... 30

Approci per la sincronizzazione ............................................................................................................................ 31

Approccio Hardware ......................................................................................................................................... 31

Approccio Software .......................................................................................................................................... 36

2
Appunti di Sistemi Operativi Teoria

Approccio basato su Sistema Operativo .......................................................................................................... 42

Altre Soluzioni per la Sincronizzazione ............................................................................................................. 46

Problemi di sincronizzazione ................................................................................................................................ 51

Produttore e consumatore ............................................................................................................................... 51

Lettore – Scrittore ............................................................................................................................................. 59

Cinque filosofi a cena ........................................................................................................................................ 62

Barbiere addormentato .................................................................................................................................... 65

Deadlock .................................................................................................................................................................... 67

Caratterizzazione del deadlock ............................................................................................................................. 67

Risoluzione dei deadlock ....................................................................................................................................... 67

Evitare il deadlock ................................................................................................................................................. 68

Rifiuto di allocazione ......................................................................................................................................... 68

Algoritmo del Banchiere ................................................................................................................................... 68

Prevenire il deadlock ............................................................................................................................................. 69

Ignorare il deadlock ............................................................................................................................................... 69

Memoria .................................................................................................................................................................... 70

Swapping ............................................................................................................................................................... 71

Binding ................................................................................................................................................................... 71

Partizionamento ........................................................................................................................................................ 72

Partizionamento fisso ....................................................................................................................................... 72

Partizionamento variabile................................................................................................................................. 73

Buddy system .................................................................................................................................................... 74

Allocatore Potenza del 2 ................................................................................................................................... 75

Allocazione della memoria.................................................................................................................................... 75

Allocazione non contigua.................................................................................................................................. 75

Paginazione............................................................................................................................................................ 76

Tabella delle pagine .......................................................................................................................................... 76

Dimensione ottimale delle pagine........................................................................................................................ 78

Indirizzi della memoria .......................................................................................................................................... 78

3
Appunti di Sistemi Operativi Teoria

Traduzione indirizzi ............................................................................................................................................... 79

Page fault ............................................................................................................................................................... 80

TLB (Traslation Lookside Buffer) ........................................................................................................................... 82

EAT ......................................................................................................................................................................... 83

Prima formula senza TLB .................................................................................................................................. 83

Seconda formula con TLB ................................................................................................................................. 83

Formula complete ............................................................................................................................................. 84

Sostituzione delle pagine ...................................................................................................................................... 84

Algoritmi di sostituzione ....................................................................................................................................... 85

Sostituzione Ottimale ....................................................................................................................................... 85

Algoritmo FIFO .................................................................................................................................................. 85

Algoritmo LRU ................................................................................................................................................... 86

Algoritmo Clock ................................................................................................................................................. 87

Strategie alternative .............................................................................................................................................. 88

Algoritmo NRU (Not Recently Used) ................................................................................................................ 88

Allocazione Frame ai processi .......................................................................................................................... 88

Il modello a Working Set................................................................................................................................... 89

Algoritmo Page Fault Frequency ...................................................................................................................... 90

Riepilogo ................................................................................................................................................................ 91

Segmentazione ...................................................................................................................................................... 91

Segmentazione paginata....................................................................................................................................... 92

Allocazione della memoria del kernel .................................................................................................................. 93

Casi studio.............................................................................................................................................................. 93

Gestione della memoria in Unix ....................................................................................................................... 93

Allocatore Lazy Buddy (utilizzato da Unix) ....................................................................................................... 93

Gestione della memoria in Linux ...................................................................................................................... 93

Gestione della memoria in Windows ............................................................................................................... 94

FileSystem .................................................................................................................................................................. 95

Tipi di file................................................................................................................................................................ 97

4
Appunti di Sistemi Operativi Teoria

Attributi di un file .............................................................................................................................................. 97

Operazioni sui file.............................................................................................................................................. 98

Tipologie di accesso ai file ..................................................................................................................................... 98

Pila ..................................................................................................................................................................... 98

Sequenziale ....................................................................................................................................................... 98

File sequenziale indicizzato ....................................................................................................................... 98

File diretto o Hash ............................................................................................................................................. 99

Allocazione di File ................................................................................................................................................ 100

Metodi di organizzazione dei blocchi ............................................................................................................. 100

Metodi di allocazione dei file .............................................................................................................................. 101

Allocazione contigua ....................................................................................................................................... 101

Allocazione non contigua................................................................................................................................ 101

File allocation table (FAT) ............................................................................................................................... 102

Allocazione indicizzata .................................................................................................................................... 103

File System in Unix .............................................................................................................................................. 105

I-NODE ............................................................................................................................................................. 105

Superblocco ..................................................................................................................................................... 106

Organizzazione logica .......................................................................................................................................... 106

Struttura a due livelli ....................................................................................................................................... 106

Struttura ad albero.......................................................................................................................................... 107

.............................................................................................................................................................................. 107

Struttura a grafi ............................................................................................................................................... 108

Affidabilità del file system ................................................................................................................................... 108

Dump fisico...................................................................................................................................................... 109

Dump logico .................................................................................................................................................... 109

JSF ........................................................................................................................................................................ 109

FSV ....................................................................................................................................................................... 110

Dischi magnetici ...................................................................................................................................................... 110

Parametri di prestazioni del disco ...................................................................................................................... 111

5
Appunti di Sistemi Operativi Teoria

Raid .......................................................................................................................................................................... 112

Raid 0 ................................................................................................................................................................... 112

Raid 1 ................................................................................................................................................................... 113

Raid 2 ................................................................................................................................................................... 113

Raid 3 ................................................................................................................................................................... 114

Raid 4 ................................................................................................................................................................... 114

Raid 5 ................................................................................................................................................................... 115

Raid 6 ................................................................................................................................................................... 115

Raid 0 + 1 ............................................................................................................................................................. 116

Raid 1 + 0 ............................................................................................................................................................. 116

Scheduling del disco ................................................................................................................................................ 117

First come first served (FCFS).............................................................................................................................. 117

Shortest seek time first (SSTF) ............................................................................................................................ 117

Scan ...................................................................................................................................................................... 117

Look...................................................................................................................................................................... 117

C-Scan .................................................................................................................................................................. 117

C-Look .................................................................................................................................................................. 117

Sicurezza e protezione ............................................................................................................................................ 118

Obiettivi della sicurezza e della protezione........................................................................................................ 118

Attacchi alla sicurezza ......................................................................................................................................... 118

Minacce: Trojan,virus,worm ............................................................................................................................... 118

Sicurezza in Windows .......................................................................................................................................... 119

Cifratura ............................................................................................................................................................... 119

Cifratura Simmetrica ....................................................................................................................................... 120

Cifratura Asimmetrica ..................................................................................................................................... 120

Tecniche di cifratura ....................................................................................................................................... 121

Algoritmi .............................................................................................................................................................. 122

Des ................................................................................................................................................................... 122

AES ................................................................................................................................................................... 123

6
Appunti di Sistemi Operativi Teoria

RSA ................................................................................................................................................................... 124

Algoritmo dello zaino ...................................................................................................................................... 125

Matrice di controllo degli accessi (ACM) ............................................................................................................ 128

Liste di controllo degli accessi (ACL) ................................................................................................................... 128

Capability list (C-list) ............................................................................................................................................ 128

Dominio di protezione ........................................................................................................................................ 128

Utenti in Unix....................................................................................................................................................... 129

Possibili Domande all’orale ..................................................................................................................................... 130

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

dello zaino  Aggiunta la complessità del Buddy System

 Inserimento dell’algoritmo dello zaino  Migliorata la sincronizzazione con approccio

superincreasing hardware, aggiungendo anche l’struzione XCHG

 gestione dettagliata della system-call  Rifatta e completata la sincronizzazione

 Inserimento dell’EAT nelle varie versioni e mediante test-and-set

spiegazione  Rifacimento degli algoritmi di sincro : 1,2

 Inseriti Dump logici e fisici del disco tentativo,dekker,peterson,panettiere

 Tipologie di accesso ai file come Pila, sequenziale  Rifacimento dei semafori

indicizzata, hash (binario,mutex,contatore)

 Gestione dettagliata dell I/O tramite DMA e  Inserimento della Regione critica, prod-cons

organizzazione dello stesso tramite regione critica

 Migliorata la segmentazione paginata  Inserita la tabella delle pagine hash

 Rifacimento totale degli algoritmi di RSA,AES e  La sicurezza in Windows

DES  Aggiunto Allocatore McKusick-Karels

 Inserimento della struttura del file system con  Aggiunto Allocatore Lazy buddy

livelli  Aggiunto Allocatore Slab

 Inserimento della proprietà di Invarianza dei  Aggiunto il produttore consumatore con variabili

semafori di condizione

 Aggiunta l’user-area  Aggiunto il barbiere addoremntato mediante

 Miglioramento della politica di scheduling variabili di condizione

Round Robin  Aggiunto algoritmo NRU

 Aggiunto scheduling Earlier deadline first 


 Aggiunta la notazione polacca-posfista

 Aggiunto monitor di Hoare

 Aggiunto monitor di Lampson/redell

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

o Stato dei dispositivi di I/O (disponibile, occupato)


o Stato delle operazioni di I/O (lettura,scrittura)
o Informazioni riguardanti i buffer utilizzati per il trasferimento
dei dati da e verso la memoria centrale
 Tabella dei file aperti (utilizzata dal file system), ), contiene per ogni record
le informazioni relative a:
o Id del file aperto
o Dove si trova il file allocato nella memoria secondaria
o Offset all interno del file
o Attributi generali del file
- Struttura modulare, ricorda la struttura del Sistema UNIX.
Il Sistema operativo può essere visto come:
 Interfaccia tra l’utente e il sistema, cioè permette all’utente di interagire con il
sistema hardware sottostante per risolvere problemi.
 Macchina virtuale, definisce una serie di machine virtuali, cioè realizza mediante
astrazione sulla macchina fisica tante copie quanti sono i processi che devono andare
in esecuzione questo da l’impressione all’utente di avere a disposizione l’intera
macchina per ogni programma. Quest’ operazione è detta Multiplazione e la si
effettua grazie a tre passi:
1) Context switch, passaggio da un processo ad un altro
2) Dispatching dei processi, indica la timeslice di tempo dedicate ad ogni processo
3) Riconoscimento dell’hardware I/O, riconosce I dispositive per comunicare con
il sistema
 Gestore di risorse, controlla e coordina il funzionamento contemporaneo dei
componenti del sistema.

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).

Entrambi gli interrupt si dividono in interrupt hardware ed interrupt software. Ad ogni

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

Il ciclo fondamentale della CPU si compone di tre fasi:


1) Fase Fetch (Istruction Fetch). L istruzione da eseguire, il cui indirizzo è registrato
in PI, viene prelevato dalla memoria Centrale e spostata attraverso il registro di
Transito in appositi registri dell’Unità Centrale da dove condizionerà lo sviluppo
successivo dell’algoritmo, l istruzione viene decomposta nei suoi componenti
(codice operativo, singoli operandi, informazioni ausiliarie); viene altresì
incrementato di una unità il registro PI in modo che la macchina sia pronta ad
eseguire la prossima istruzione.
2) Fase Preparazione degli Operandi (Operand Assembly). In funzione del modo di
indirizzamento specificato nell istruzione, vengono costruiti in appositi registri gli
operandi sui quali l istruzione dovrà operare
3) Fase Esecuzione (Execute). In funzione del codice operativo dell’istruzione
prelevata nella fase a) ed agendo sugli operandi nella fase b), vengono effettuate le
microperazioni necessarie per le esecuzioni dell’istruzioni, quali trasferimenti tra
registri interni, operazioni aritmetiche, accessi in memoria per registri risultati,
etc.. eseguendo quindi le operazioni desiderate.
Alla fine di ogni fase di esecuzione la CPU si chiede se è avvenuto un interrupt, in
caso affermativo richiama l’ISR (interrupt service routine per servirlo).

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

Gestione degli interrupt


Dopo l'esecuzione di ogni istruzione, la CPU controlla se sono stati generati interrupt. In caso
affermativo, la CPU esegue il gestore dell'interrupt (interrupt handler), che salva lo stato
della CPU e passa ad eseguire la routine di servizio dell'interrupt nel kernel.

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

Il multitasking, o multiprogrammazione, è quella caratteristica che ci permette di mandare


in esecuzione più programmi concorrentemente, cioè i programmi concorrono all’utilizzo
delle risorse. Il multitasking è garantito da due aspetti:
 Un utente può mandare in esecuzione più programmi concorrentemente
 Un programma applicativo può mandare in esecuzione parti di se stesso configurate
o come processi figli o come thread del processo.
I benefici del multitasking sono tre:
1. Speedup dell’elaborazione, maggiore velocità di esecuzione per cui se un programma
attende dati da dispositivi di I/O, la CPU si dedica ad altri processi.
2. Priorità per le funzioni critiche, può verificarsi un cambio di priorità
dell’elaborazione ovvero un processo genitore può assegnare priorità ai processi figli.
3. Protegge un processo genitore dai fault dei figli.

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

viene prelazionato poiché il kernel decide di schedulare un altro processo (es: un


processo a priorità più alta va nello stato ready oppure la time-slice del processo si
esaurisce).
 RUNNING -> BLOCKED: un processo passa dallo stato running a quello blocked
quando effettua una system call per richiedere l'uso di una risorsa o quando rimane
in attesa di un evento. Un processo bloccato si trova in memoria, ma non
necessariamente in memoria centrale (ad esempio in memoria swap).
 BLOCKED -> READY: quando la richiesta del processo viene soddisfatta o quando si
verifica l'evento, il processo passa dallo stato blocked a quello ready.

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

solo quando il processo è in esecuzione.

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

Un thread è un unità di impiego all’interno di un processo che usa le risorse di un processo.


Un processo può contenere più thread, ciascuno dei quali evolve in modo logicamente
separato dagli altri thread. Un thread differisce da un processo nel fatto che a esso non sono
allocate risorse. Questa differenza riduce l'overhead della commutazione tra thread rispetto
all'overhead della commutazione tra processi. Un processo crea un thread mediante una
system call. Il thread non possiede risorse proprie, quindi non ha un contesto; viene eseguito
usando il contesto del processo e in tal modo accede alle risorse del processo. ogni thread è
un'istanza del programma, per cui ha un proprio stack e un proprio Thread Control Block
(TCB), analogo al PCB e contenente le seguenti informazioni:
- informazioni per la schedulazione dei thread: thread ID, priorità, stato;
- stato della CPU: contenuto della PSW e dei registri GPR;
- puntatore al PCB del processo genitore;
- puntatore al TCB, usato per creare le liste di TCB per la schedulazione.
Nel TCB rispetto al PCB mancano: la tabella dei file aperti e la tabella della memoria poiche
sono condivise con il processo creante.
Un thread può essere: attivo, in attesa,pronto ma non sospeso. La sospensione di un
processo sospende tutti i suoi thread cosi come la terminazione.
Il sistema operativo possiede una tabella dei thread nella quale memorizza le informazioni
come il PC e l’IR per ogni thread. Questa tabella risiede nel kernel che risiede a sua volta
nel kernel space.
VANTAGGI DEI THREAD RISPETTO AI PROCESSI
- minor overhead relativamente alla creazione e alla commutazione
- Un altro vantaggio rispetto ai processi è la progettazione semplificata. Infatti l'uso
dei thread può semplificare la progettazione e la codifica delle applicazioni che
servono le richieste concorrentemente.

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

Scheduler a breve termine


E' detto anche dispatcher o scheduler. Decide quale processo nello stato ready può andare
in esecuzione. inoltre, può anche decidere il tempo di utilizzo della CPU per il processo
selezionato.
I momenti in cui può intervenire lo scheduler a breve termine sono quattro:
- quando un processo passa dallo stato running allo stato blocked per selezionare
quale altro processo ready andrà in esecuzione quando un processo passa dallo
stato blocker allo stato ready per determinare con quali altri processi ready
compete
- quando un processo passa dallo stato running allo stato ready (es. per na
interruzione) per determinare se il processo tornerà in esecuzione subito oppure
no quando un processo termina per selezionare quale processo verrà eseguito

Efficienza dello scheduler a breve termine


L’efficienza dello scheduler a breve termine viene misurato in base ad alcuni criteri:
 Attività di CPU, indica la percentuale di tempo di CPU che viene utilizzata per i
processi utente;
 Livello di multiprogrammazione, indica il numero di processi che risiedono in
memoria centrale e possono essere quindi eseguiti;
 Tempo di attesa, indica il tempo che il processo trascorre nella ready queue ivi
compreso il tempo di context-switch
 Tempo di tournaround, indica il tempo di completamento relativo al CPU-Burst
 Tempo di risposta, indica il tempo effettivo di risposta e si calcola come tempo di
CPU burst + Tempo di attesa/Tempo di CPU-Burst
 Througput, indica il numero di processi in esecuzione nell’unità di tempo
 Fairness, indica una sorta di equità di trattamento tra i processi

19
Appunti di Sistemi Operativi Teoria

Scheduler a medio termine


Lo scheduler a medio termine gestisce la permanenza in memoria dei processi non in
esecuzione. In pratica decide quali processi possono risiedere in memoria e quali sul disco.
Le operazioni di carico (swap in) e scarico (swap out) sono comunque effettua dal gestore
della memoria

Scheduler a lungo termine


Lo scheduler a lungo termine decide quale processo entra nella coda dei processi ready tra
quelli che la richiedono, perciò controlla il grado di multiprogrammazione (il numero di
processi presenti in memoria). Lo scheduler a lungo termine può ritardare l'ammissione di
una richiesta per due motivi:
1) non riesce ad allocare risorse sufficienti
2) l'ammissione della richiesta porterebbe ad un calo delle prestazioni del sistema

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à

Politiche non preemptive


La politica di scheduling non preemptive (senza prelazione) non dà la possibilità di
interrompere un processo in esecuzione. Essa seleziona un processo e lo lascia in esecuzione
finchè non si blocca (per attendere un evento o richiedere una risorsa) oppure finchè non
completa le sue operazioni rilasciando volontariamente la CPU. Poiché una richiesta non è
mai prelazionata, lo scheduler ha soltanto la funzione di riordinare le richieste per migliorare
il servizio utente o le prestazioni del sistema.
Le tre politiche di scheduling non preemptive sono:
- Scheduling First Come, First Served (FCFS)
- Scheduling Shortest Job First (SJF) nella versione non preemptive (SNPF)
- Scheduling Highest Response Ratio Next (HRRN)

20
Appunti di Sistemi Operativi Teoria

Scheduling First Come, First Served (FCFS)

I processi sono schedulati nell'ordine in


cui giungono al sistema.
Cioè il primo processo ad essere eseguito
è quello che per primo ha richiesto la
CPU. In pratica, i processi ready sono
organizzati come una coda FIFO e i
processi che richiedono la CPU vengono
inseriti alla fine di questa coda. E' un
algoritmo che privilegia i processi CPU
bound, infatti questo algoritmo presenta
il problema effetto convoglio: i processi
che richiedono meno tempo di CPU (I/O
bound) devono attendere che i processi
che richiedono molto tempo di CPU (CPU bound) liberino la CPU.

Scheduling Shortest Job First (SJF) non preemptive (SNPF)


Seleziona il processo in attesa che userà
la CPU per minor tempo.
Se due processi hanno lo stesso tempo
di esecuzione, verrà applicato lo
scheduling FCFS. In pratica, le
richieste brevi tendono a ricevere prima
l'uso della CPU. In pratica, è come se il
CPU-BURST fosse la priorità. La prima è
che è necessario conoscere in anticipo i
tempi di esecuzione (tempo di servizio)
dei vari processi. Visto che il SO non
conosce a priori i tempi di servizio,
occorre effettuare una stima dei CPU
burst. Questa può essere effettuata conoscendo la 'storia passata' in modo tale da poter fare
una stima del 'futuro'. La seconda è che possiede un potenziale problema di starvation, in
cui è possibile che un processo rimanga in attesa troppo tempo prima di essere completato
se vengono aggiunti continuamente piccoli processi alla coda dei processi pronti.

21
Appunti di Sistemi Operativi Teoria

Scheduling Highest Response Ratio Next (HRRN)


questo algoritmo viene
utilizzato per prevenire
l'aging, ossia l'attesa
eccessiva dei processi
molto lunghi scavalcati
da quelli più brevi, che
avviene negli algoritmi
SJF. Questa politica
calcola i rapporti di
risposta di tutti i
processi nel sistema
secondo la formula:

(Tempo di servizio + Tempo di attesa ) / tempo di servizio

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

Scheduling Shortest Job First (SJF) preemptive


si differenzia dallo
SNPF per il fatto che,
quando viene
sottomesso un nuovo
processo la cui durata è
minore del tempo
necessario al processo
in esecuzione per
concludere le proprie
operazioni, lo scheduler
provvede ad effettuare
un context switch per
assegnare l'uso della
CPU al nuovo processo.
In caso di uguaglianza
viene selezionato il processo che non è stato elaborato per il periodo di tempo più lungo.

Round robin (RR)


Ad ogni processo viene assegnato un
intervallo di tempo, chiamato
quanto (time slice), durante il quale
al processo è assegnato l'uso della
CPU. Per scandire i
quanti, alla fine di
ognuno di essi viene
generato un timer
interrupt. Se alla
fine del quanto, il
processo non ha
terminato le sue
operazioni, allora
viene prelazionato e
inserito di nuovo
nella coda, e la CPU
viene assegnata ad un altro processo. Se prima della fine del quanto, il processo si blocca o
termina le sue operazioni, allora viene selezionato un altro processo a cui assegnare la CPU.

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.

Least completed next (LCN)


La politica LCN seleziona il
processo che ha utilizzato il
minimo tempo di CPU. In caso di
uguaglianza lo scheduler
seleziona il processo che non è
stato elaborato per il periodo di
tempo più lungo.

24
Appunti di Sistemi Operativi Teoria

Con priorità o senza priorità


- Le politiche che usano la priorità selezionano i processi a cui attribuire l'uso della CPU
proprio in base alla priorità acquisita da ciascuno di essi. Queste politiche sono
necessarie nei sistemi real-time e nei sistemi interattivi.
Le priorità possono essere statiche o dinamiche:
o Statiche , invariabili
o Dinamiche , che possono variare nel tempo
- Le politiche che non usano la priorità considerano i processi ‚equivalenti‛, cioè tutto sullo
stesso piano senza privilegiare l'uno rispetto ad un altro. Queste politiche sono basate su
strategie di ordinamento First Come Fist Served.

Scheduling a code multiple


Esso combina lo scheduling basato su priorità e quello round-robin per fornire una buona
combinazione tra prestazione del sistema e tempi di risposta. Uno scheduler multilivello
utilizza varie code di processi pronti, e ad ogni classe è associata una priorità. Alla coda con
priorità più alta viene assegnato un quanto più piccolo, mentre alle code con priorità via via
minore viene assegnato un quanto sempre più grande. La coda con priorità più bassa avrà il
quanto più grande. I processi della classe più alta vengono eseguiti per un quanto, quelli
della classe successiva per due quanti, quelli della classe seguente per quattro quanti e così
via. Ogni qualvolta che un processo rimane in esecuzione per tutto il quanto, viene abbassato
di una classe . La scelta del processo da schedulare non avviene in modo sequenziale su
ogni coda poichè se si partisse dalla classe con priorità più alta, quelli con priorità più bassa
dovrebbero aspettare troppo per la schedulazione (starvation). Per questo motive viene
assegnata una timeslice massima di tempo per la permanenza nella coda scaduta la quale
il processo viene schedulato per il quanto assegnatogli.
In questa politica di scheduling vengono utilizzate priorità statiche, per questo motivo non
può prevenire la starvation dei processi a bassi livelli di priorità.

Scheduling a code multiple con feedback


Ciò che lo contraddistingue dallo scheduling a code multiple senza feedback è l'uso delle
priorità dinamiche, ciò permette allo scheduling di variare la priorità di un processo in
modo tale da evitare la starvation dei processi. Lo scheduler analizza il comportamento
passato di un processo per modificare, eventualmente, la sua priorità. Quindi, l'uso delle
priorità dinamiche consente ad un processo di muoversi tra le varie code presenti.

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:

(T) Tempo trascorso / (t) tempo di diritto

(T) = il tempo trascorso da quando il processo è stato lanciato.


(t) = il tempo al quale avrebbe diritto sul tempo totale di CPU

Il Tempo di Diritto è pari ad 1/n del Tempo trascorso.


L’ottimale sarebbe riuscire ad ottenere un tempo trascorso pari al tempo di diritto ma
genericamente il tempo trascorso è più piccolo per cui più piccolo è il rapporto più vuol dire
che il numeratore (cioè il tempo trascorso) deve ancora tendere al denominatore (cioè al
tempo di diritto). Il risultato del rapporto è compreso tra 0 ed 1 ma è preferibile che tenda
ad 1.
La priorità viene data ai processi con il rapport più piccolo in quanto il tempo stimato è
ancora piccolo rispetto al tempo che il processo dovrebbe avere.

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”

Ci = tempo di esecuzione in ciascun period del task


Ti = period del task i
Ci/ti = percentuale utilizzo CPU

Qualora il risultato fosse 1 rappresenterebbe il pieno utilizzo della CPU.


N.B. : è possibile che un processo vada in fault nonostante tale disuguaglianza sia
soddisfatta.

Earlier deadline first


Questo algoritmo di scheduling a priorità variabile poichè seleziona ogni volta il processo
avente Deadline più imminente. In questo algoritmo il criterio di schedulabilità è ancora
più stringente:

“Sommatoria Ci/ti <= n(2^1/n -1)”


N = numero di processi schedulabili

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

Prelazionabilità del Kernel


La prelazionabilità del kernel gioca un ruolo fondamentale nell’efficacia di uno scheduler. Un
kernel non prelazionabile gestisce un evento per volta senza interruzioni. Se I gestori degli
eventi presentano lunghi tempi di esecuzione la non prelazionabilità del kernel causa un
elevate latenza poichè il kernel non può rispondere prontamente agli interrupt. Rendere il
kernel prelazionabile resolve il problema.

28
Appunti di Sistemi Operativi Teoria

Sincronizzazione tra processi


Solitamente un'applicazione è composta da vari processi che interagiscono tra loro per il
raggiungimento di un obiettivo comune. Questi processi sono detti processi concorrenti o
processi cooperanti.
 due processi cooperano se ciascuno ha bisogno dell'altro per procedere con le
proprie operazioni.
 due processi competono se entrano in conflitto sulla ripartizione delle risorse.
In entrambi i casi occorre predisporre meccanismi di sincronizzazione e comunicazione che
permettano al processo di gestire la cooperazione e la competizione. Il modo nel quale I
processi comunicano in entrambi I casi possono essere molteplici, uno di questi è l’uso della
memoria condivisa (shell memory) dove la comunicazione avviene per locazioni di memoria
nella memoria central condivisa. L’altra possibilità è quella di avere i processi che risiedono
su machine differenti quindi non esiste memoria condivisa, in questo caso la soluzione è
comunicare sulla rete (message passing).
Un insieme di processi cooperanti possono condividere parti dei dati che possono risiedere
in memoria centrale. Quando questi processi comunicano tra di loro il punto di
comunicazione è detto Punto di Sincronizzazione.
Un insieme di processi in competizione hanno bisogno di regolamentare l’accesso alla risorsa
che si contendono poiché potrebbero trovarsi in conflitto.
Quando due o più processi accedono ad un area di memoria condivisa e modificano un valore
ovviamente in base all’ordine di accesso troveremo un valore anziché un altro e questo può
pregiudicare le azioni successive. Quindi va necessariamente regolamentato l’accesso all’area
di memoria condivisa, quando avviene l’accesso si dice che il processo va in sezione critica.

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

Condizioni per una corretta sincronizzazione


 Mutua esclusione, solo un processo per volta può accedere in sezione critica;
 Portabilità, indipendenza dalla velocità dei singoli processori
 Progresso, un processo che in un dato momento non necessita di andare in sezione
critica non può bloccare gli altri processi;
 Attesa limitata, nessun processo deve attendere per un tempo indefinito prima di
entrare in sezione critica.
Queste ultime due condizioni, assieme, garantiscono che non si verificherà mai il fenomeno
della starvation.

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

Quando un insieme di istruzioni rispetta le condizioni di Bernstein il loro esito complessivo


sarà sempre lo stesso indipendentemente dall'ordine e dalla velocità di esecuzione, altrimenti
in caso di violazione, gli errori dipenderanno dall'ordine di esecuzione e dalle velocità relative
generando race condition.
E’ importante notare che no si impone nessuna condizione sui domini, infatti potrebbero
utilizzare lo stesso dominio.
Esempio:
Procedura P
Begin Dominio (P) = { A, B, X }
X = A + X; Rango (P) = { X, Y }
Y = A * B;
End

Approci per la sincronizzazione


Ci sono vari modi per soddisfare i requisiti della mutua esclusione:
- Approcci hardware. Istruzioni macchina speciali e disabilitazione delle interruzioni, che
hanno il vantaggio di ridurre l'overhead, ma non sono soddisfacenti
- Approcci software (o algoritmico). Consistono in algoritmi che gestiscono la mutua
esclusione senza alcun supporto da parte del sistema operativo o dal linguaggio di
programmazione.
- Approcci sistema operativo/linguaggio di programmazione. Consistono in costrutti,
funzioni e strutture dati.

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..

Abilitazione e disabilitazione degli interrupt


In questo caso ogni processo che ha intenzione di entrare in sezione critica disabilita gli
interrupt, così facendo il codice viene eseguito in mutua esclusione cioè nessun altro
processo che ha intenzione di entrare in sezione critica può interrompere l’esecuzione di quel
processo che solo all’uscita dalla sezione critica riabilita gli interrupt.
Questa soluzione è efficace soltanto se il codice della sezione critica è breve , poiché la
disabilitazione prolungata degli interrupt equivale ad una monopolizzazione della CPU. È
inaffidabile poiché un fault all’interno della sezione critica con gli interrupt disabilitati

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.

Istruzione test and set

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.

Istruzione XCHG (o SWAP)


È un algoritmo di scambio di due variabili:

Analizziamo il comportamento di un processo Pi:

33
Appunti di Sistemi Operativi Teoria

In questo caso abbiamo due variabili:


 Key (utilizzata localmente dal processo)
 Lock (inizializzata a 0) è una variabile condivisa.
L’idea è quella di scambiare il valore tra lock e key.
SPIEGAZIONE
Se un processo vuole entrare in sezione critica setta la
variabile Key = 1. Quindi key indica l’intenzione di un
processo di entrare o meno in sezione critica.
Dopodichè il processo Pi deve accertarsi che sia il suo
turno, per fare ciò scambia il valore di lock = 0 con
quello di key = 1.
Quindi avremo lock =1 e key = 0, questo permette al processo Pi di entrare in sezione critica
poiché si esce dal repeat e in più bloccherà tutti gli altri processi che vorranno entrare in
sezione critica poiché tentano di scambiare il valore di lock = 1 con il loro valore di key = 1 e
non usciranno dal repeat.
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 setta key = 1.
 L’attesa limitata NON è garantita poiché è possibile che un processo non venga mai
schedulato e quindi non vada mai in esecuzione.

34
Appunti di Sistemi Operativi Teoria

Soluzione proposta utilizzando TEST-AND-SET


Il processo che esce dalla propria
sezione critica designa attraverso
una coda circolare il prossimo
processo che può entrare in sezione
critica. Qualsiasi processo che
intende entrare in sezione critica
attenderà al più N-1 turni.
SPIEGAZIONE
Questa soluzione soddisfa tutti i
requisiti che deve avere una
soluzione corretta al provlema della
sezione critica. Le strutture condivise
sono: boolean waiting[n], boolean
lock.
 Per dimostrare che soddisfa il
requisito della mutua escluzione si
considera che il processo Pi può
entrare nella propria sezione critica
solo se waiting[i]==false oppure
key==false. Il valore di key può diventare false solo se si esegue testset. Il primo
processo che esegue testset trova key==false, tutti gli altri fanno busy waiting. La
variabile waiting[i] può diventare false solo se un altro processo esce dalla propria
sezione critica, solo una variabile waiting[i] vale false, il che consente di rispettare il
requisito di mutua esclusione.
 Per dimostrare che l’algoritmo soddisfa il requisito di progresso basta osservare che
le argomentazioni fatte per la mutua esclusione valgono anche in questo caso, infatti
un processo che esce dalla sezione critica o imposta key = false oppure waiting[i] =
false.
Entrambe consentono ad un processo che attende di entrare in sezione critica di
procedere.
 Per dimostrare che l’algoritmo soddisfa il requisito di attesa limitata occorre
osservare che un processo quando lascia la propria sezione critica scandisce il vettore
waiting nell’ordinamento ciclico (i+1,i+2, n-1,0,…,i1) e designa il primo processo in
questo ordinamento presente nella sezione di ingresso (waiting[j] == true) come il
primo processo che deve entrare nella propria sezione critica. Qualsiasi processo che

35
Appunti di Sistemi Operativi Teoria

attende di entrare nella propria sezione può farlo entro n - 1 turni.

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

In questo algoritmo vengono utilizzati


due variabili, c1 e c2, che possono essere
considerate rispettivamente come flag
che indicano l’intenzione dei processi di
entrare in sezione critica. Un processo
prima di entrare in sezione critica
dimostra la sua intenzione di entrarci
ponendo il proprio Flag = true.

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

L'algoritmo di Dekker combina le soluzioni


adottate nei due casi precedenti. Per evitare i
vari problemi è necessario imporre un ordine
di attività dei due processi. Se c'è
competizione per l'entrata in sezione critica,
si può usare la variabile turn del primo
tentativo per indicare a qual processo
dovrebbe essere consentita l'entrata in
sezione critica. Nel caso in cui non ci sia
competizione, turn non ha alcun effetto. Le
variabili c1 e c2 sono usate come flag di stato
proprio come nel secondo tentativo. IL
processo Pi prima di entrare in sezione critica
dichiara la sua intenzione di entrarci e verifica se l’altro processo è in sezione critica,
naturalmente se questo è vero fa busy waiting. Quando il processo in sezione critica termina
passa il turno all’altro processo.
SPIEGAZIONE
Entriamo nel Parbegin, il processo P1 dichiara la sua intenzione di voler entrare in sezione
critica e setta C1 = 0, controlla quindi se P2 è già in sezione critica ( C2 = 0 ) allora se è cosi
verifica se è anche il suo turno (turno = 2) se è effettivamente cosi reimposta la sua intenzione
a voler entrare in sezione critica a FALSE (c1 = 1) ed inizia ad attendere (while turn = 2 do
{niente}) che P2 esca dalla sezione critica. Se ne accorge poiché turno sarà settato a 1 e non
più a 2. Quindi appena questo accade P1 imposta la sua intenzione di voler entrare in sezione

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

Questo algoritmo è stato


sviluppato nel 1974 ed ha
lo scopo di risolvere il
problema della sezione
critica per n processi. E'
noto come algoritmo del
panettiere ed è basato su
uno schema di servizio
comunemente usato nelle
panetterie. E’ un
estensione di Peterson in
quanto i processi che
vogliono entrare in sezione
critica non sono più 2 ma
N. L’array CHOOSING
indica l’intenzione di
scegliere un numero, e
quindi l’intenzione di entrare in sezione critica. Se un processo non ha intenzione di entrare
in sezione critica questo numero è 0, altrimenti è diverso da 0.
SPIEGAZIONE
Inizialmente tutti i numeri sono 0 e tutti i choosing vengono settati a false.
Entriamo nel parbegin, il processo Pi decide di scegliere un numero e setta
CHOOSING[i]=TRUE, dopodichè prende il massimo di N numeri condivisi
(MAX(number[0]…number[n-1])) e gli somma 1 (SUP), poi resetta CHOOSING=FALSE. Dopo
aver fatto questo Po deve capire se è il suo turno e per fare ciò deve ciclare su tutti gli altri
numeri (for j=0 to n-1). Quindi, la prima cosa che fa è verificare se un certo Processo J ha
intenzione di scegliere un numero e quindi di entrare in sezione critica
(CHOOSING[j]=TRUE), se è vero significa che Pj sta scegliendo un numero e Pi deve attendere
che termini la scelta.
Dopodichè lo visita, cioè verifica se NUMBER[j]!=0, perché un determinato processo J
potrebbe aver scelto il numero, essere entrato in sezione critica, aver fatto le operazioni,
essere uscito e aver settato NUMBER[j]=0 tutto questo in modo così veloce che Pi non
potrebbe accorgersene. La soluzione è indipendente dalla velocità dei processi.
Quindi se NUMBER[j]!=0 significa che il processo Pj ha scelto il numero ma non è ancora ne

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

Approccio basato su Sistema Operativo


Le soluzioni che si basano sull'approccio basato su linguaggio di programmazioni usano
meccanismi di IPC come i semafori, i monitor o lo scambio di messaggi.

Semafori
Un semaforo è un costrutto linguistico che viene utilizzato per effettuare la sincronizzazione
tra i processi indipendentemente dalla velocità dei processori.

La soluzione chef u progettata inizialmente fu introdotta nell’ambito di un linguaggio di


programmazione e successivamente spostato nell’ambito del Sistema Operativo, questo
perchè nel primo ambito vi era Busy Waiting cioè l’attesa del processo Pi che voleva entrare
in sezione critica NON veniva eliminate, ma il processo attendeva fin quando la richiesta
fatta non veniva evasa. Gli stati utilizzati erano solo: Ready e Running.
Successivamente si pensò di spostare il costrutto linguistico nell’ambito del Sistema
Operativo, cioè in una libreria di Sistema, in modo tale che tutte le operazioni venissero
effettuate in modalità kernel e quindi dal Sistema operative che è l’unico in grado di spostare
un processo dallo stato Running ad uno stato Bloccato, lasciando così spazio ad altri processi
di essere schedulati ed eseguiti.
Questa libreria di Sistema include la gestione dei semafori, cioè l’entry section e l’exit
section fanno riferimento a delle System-call. Queste system-call sono : wait e signal.
 Wait, (entry section), verifica e consente l’accesso alla sezione critica al processo Pi;
 Signal (exit section), viene invocate all’uscita dalla sezione critica ed effettua il
rilascio della risorsa utilizzata dal processo Pi.
Il codice relativo alla wait e alla signal deve essere breve ed affidabile così da evitare Fault.
In generale, un semaforo può essere inizializzato:
 Ad un numero intero positivo, indica il numero di risorse alle quali I processi
possono accedere anche non in mutual esclusione (semaforo contatore)
 Ad 1, indica che si deve garantire la mutual esclusione per I processi che vogliono

42
Appunti di Sistemi Operativi Teoria

entrare in sezione critica.


 Ad 0, indica che un processo deve essere eseguito prima di un altro. Ovviamente il
processo che effettua la wait sul semaforo è quello che deve attendere.

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

Mutua esclusione con semaforo binario

Il semaforo è dichiarato come una variabile semaforica di tipo semaforo(struct) settata ad 1.


Cioè vi è SOLO una risorsa condivisa disponibile e quindi l’accesso in mutua esclusione nella
sezione critica può avvenire per un solo processo per volta.
SPIEGAZIONE
Entriamo nel Parbegin, il primo processo che effettua la Wait setta a 0 il valore del semaforo
(S=0), quindi l’IF della wait (S>0) fallisce e il processo viene bloccato. Si troveranno PIU’
processi bloccati in attesa sul semaforo ma questa soluzione NON fornisce il numero di
processi in attesa. All’uscita dalla sezione critica il processo Pi esegue la signal sul semaforo,
la quale se vi è un processo in attesa lo risveglia altrimenti incrementa il valore del semaforo.

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.

Altre Soluzioni per la Sincronizzazione


Oltre alla soluzione di tipo semaforico, durante il corso degli anni sono state proposte altre
soluzioni:
 Monitor
 Regione critica
 Message Passing

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

Struttura del monitor

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

Naming dei processi


Una problematica molto importante nello scambio di messaggi è l'identificazione per nome
(Naming) dei processi, cioè la denominazione dei processi mittente e destinatario nelle
chiamate send e receive. I nomi dei processi mittente e destinatario, o sono indicati
esplicitamente nelle istruzioni send e receive, o sono dedotti dal kernel in un altro modo.
Abbiamo due possibili schemi per specificare i processi nelle send e nelle receive.
1. Con l'indirizzamento diretto i processi mittente e destinatario dichiarano il proprio
nome.
2. Con l'indirizzamento indiretto i processi non specificano i rispettivi nomi nelle
istruzioni send e receive. In questo caso i messaggi non viaggiano direttamente dal
mittente al destinatario, ma sono mandati ad una struttura dati condivisa che si
compone di code che contengono contemporaneamente i messaggi. Questa struttura
prende il nome di mailbox e possiede tre caratteristiche:
1. Ha un nome unico
2. Il proprietario della mailbox è tipicamente il processo che l'ha creata. Solo il
proprietario del processo può ricevere i messaggi da una mailbox.
3. Ciascun processo che è a conoscenza del nome della mailbox gli può inviare messaggi
(al processo utente della mailbox). In questo modo, i processi mittenti e destinatari
utilizzando il nome di una mailbox, piuttosto che i rispettivi nomi, nelle istruzioni
send e receive
Le relazioni tra mittenti e destinatari possono essere uno a uno, uno a molti, molti a molti.
L'associazione dei processi con le mailbox può essere statica o dinamica. Spesso una
mailbox è associata staticamente ad un solo processo in particolare se la relazione tra
mittente e destinatario è di tipo uno a uno. Mentre se la relazione è di tipo uno a molti o molti
a molti allora si utilizzano mailbox con associazioni dinamiche.
L'uso di una mailbox ha i seguenti vantaggi:
- anonimato del destinatario, infatti una mailbox consente al mittente di non conoscere
l'identità del destinatario;
- classificazione dei messaggi, un processo può creare diverse mailbox e usare ognuna
per ricevere i messaggi di un tipo specifico consentendo una semplice classificazione dei
messaggi

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

Produttore-Consumatore mediante Sezioni Critiche

 Il produttore utilizza la variabile booleana PRODOTTO per interrompere il ciclo while


dopo aver prodotto un element e controlla ripetutamente se esistono buffer vuoti. non
appena ne trova uno, inserisce l'elemento nel buffer e imposta a true la variabile
PRODOTTO
 Il consumatore usa la variabile booleana CONSUMATO per interrompere il ciclo while
dopo che ha consumato un element e controlla ripetutamente se esistono buffer pieni.
Non appena ne trova uno estrae l'elemento dal buffer e imposta a true la variabile
CONSUMATO.
Questa soluzione ha due problemi:
1. visto che entrambi gli accessi al buffer si trovano in sezioni critiche, allora un solo
processo per volta, produttore o consumatore, può accedere al buffer in ogni istante
di tempo anche se abbiamo a disposizione più buffer
2. entrambi i processi vanno in attesa attiva quando controllano se ci sono buffer pieni
e buffer vuoti.

52
Appunti di Sistemi Operativi Teoria

Produttore-Consumatore mediante Semafori

Il pool di buffer è rappresentato da un array di buffer con un singolo elemento all'interno.


Vengono dichiarati due semafori, pieno e vuoto. I valori dei semafori vuoto e pieno indicano
il numero di buffer, rispettivamente, vuoti e pieni, per cui sono inizializzati, rispettivamente,
a n e a 0. prod_ptr e cons_ptr sono usati come indici dell'array buffer e sono inizializzati a
0.
SPIEGAZIONE
Il produttore aspetta un buffer vuoto con una wait(vuoto). Quando sono disponibili buffer
vuoti, inserisce un elemento nel buffer e aggiorna l'indice prod_ptr. Dopo aver completato
l'operazione di inserimento effettua una signal(pieno) per permettere al consumatore di
entrare nella sua sezione critica.
Il consumatore aspetta un buffer pieno con una wait(pieno). Quando sono disponibili buffer
pieni, estrae un elemento dal buffer e aggiorna l'indice cons_ptr. Dopo aver completato
l'operazione di estrazione effettua una signal(vuoto) per permettere al produttore di entrare
nella sua sezione critica.
Dato che non è possibile predire l’ordine di schedulazione dei processi può capitare che a
volte viene eseguito un produttore, altre volte viene eseguito un consumatore.

53
Appunti di Sistemi Operativi Teoria

Produttore-Consumatore con Regioni Critiche

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

Produttore-Consumatore mediante Message-Passing

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

Esempio Produttore-Consumatore con Monitor


Se il produttore vuole caricare un oggetto prodotto all’interno del Buffer Condiviso che è
contenuto nel monitor poiché acente parte della sezione critica le procedure che vi operano
sopra,all’interno del monitor sono: immetti dato e preleva dato.
Se lo spazio all’interno del buffer termina il produttore Deve bloccarsi in attesa che il
consumatore “consumi” un elemento e segnali la possibilità di immettere un dato.
Per bloccarsi effettua una wait ma su una variabile di condizione.
L’operazione c.wait comporta l’immediata sospensione del processo. Il monitor dunque è
formato da variabili globali condivise che per il caso del produttore-consumatore è il buffer
condiviso, dagli indici IN e OUT per il caricamento e la cancellazione , da variabili di
condizione e dalle procedure di accesso al buffer (immetti e preleva). Tutti i controlli sono
demandati al Sistema Operativo.

 Itemtype buffer[n], è il buffer vero e proprio.


 Nextin, indica la posizione del successivo elemento da caricare
 Nextout, indica la posizione del successivo elemento da prelevare
 Contatore, indica il numero di elementi presenti nel buffer
 Nonpieno - Nonvuoto, sono variabili di condizione che contengono le code o meglio i
PCB dei processi in attesa

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

Produttore – Consumatore mediante Variabili di Condizione

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.

Lettore-Scrittore con priorità ai Lettori

Variabili condivise:
 Semaforo mutex := 1
 Semaforo scrittura := 1
 Numlettori := 0

Processo Lettore

59
Appunti di Sistemi Operativi Teoria

 Sem_wait(mutex), garantisce la mutual esclusione per la modifica del contatore, il


lettore dichiara la sua presenza. Deve garantire la mutual esclusione poichè
numlettori è globale.
 Numlettori++, incrementa il numero di lettori
Ora bisognerebbe eddettuare la sem:signal(mutex) ma se siamo in presenza del primo lettore
ad accedere bisogna bloccare subito lo scrittore e poi leggere quindi, per garantire la priorità
ai lettori:
 If(numlettori==1) sem_wait(scrittura), cioè se sono il primo lettore blocco lo scrittore
ponendo a 0 il semaforo di scrittura. Questo garantisce che se concorrentemente lo
scrittore accede a scrittura (sem_wait(scrittura)) trovando il semaforo a 0 si blocca.
N.B. : se vi sono altri lettori, lo scrittore non viene sbloccato fintantochè non vi sono più
lettori che richiedono l’accesso al dato.
Effetto lato, Se arrivassero infiniti lettori lo scrittore non accederebbe mai (Starvation)
 Sem_signal(mutex), reimposta mutex a 1, quindi rulascia la possibilità di accesso a
numlettori, da parte degli altri lettori. E’ effettuata dopo la verifica della condizione
poichè non è permesso rilasciare l’accesso a numlettori prima di bloccare lo scrittore
poichè potrenne inserirsi nell’interleaving delle istruzioni e prenotare scrittura.
 Sezione critica, dove il processo legge
 Sem_wait(mutex), riprenoto l’accesso a mutex riportandolo a 0
 Numlettori--, decrement numlettori, avendo avuto accesso alla sezione critica
 If(numlettori==0) sem_signal(scrittura), se sono l’ultimo lettore effettuo la signal su
scrittura rilasciando la possinilità allo scrittore di entrare nella sezione critica.
 Sem_signal(mutex), segnala la possibilità ad un altro lettore di accedere
La priorità al lettore viene data in concorrenza cioè solo se uno scrittore e un lettore accedono
concorrentemente. Se il primo processo è uno scrittore questo accede in sezione critica!!

60
Appunti di Sistemi Operativi Teoria

Lettore-Scrittore con priorità agli Scrittori

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

Cinque filosofi a cena


Si considerano 5 filosofi seduti ad un tavolo che compiono 2 azioni: mangiano e pensano.
Ogni filosofo per mandiage deve necessariamente utilizzate entrambe le bacchette poste ai
suoi lati.
Sono state create tre soluzioni.
Una soluzione banale prevede che per ogni bacchetta si usi un semaforo in modo da
regolamentare la gestione.
Le variabili condivise sono:
 Semaforo chopstick[5]:=1
 Filosofo i-esimo
Sono state create 3 soluzioni:
 I soluzione, prevede che solo 4 filosofi possono essere seduti contemporaneamente a
tavola
 II soluzione, un filosofo può prendere le bacchette solo se entrambe sono libere
 III soluzione, un filosofo dispari prende prima la bacchetta di sinistra e poi quella di
destra, mentre il filosofo pari fa il contrario.
L’ultima soluzione quindi esprime un ordine alle risorse per cui al filosofo viene dato un
ordine gerarchico di prelievo

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

Lo stallo è risolvibile associando alla stanza un


semaforo contatore :=4 per cui ogni filosofo dovrà
effettuare una sem_wait(stanza) prima di prenotare le
bacchette con sem_wait(chopstick[i]) . I primi 4 filosofi
possono entrare e sedersi.

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

posso mangiare, entro in sezione critica, mangio e rilascio le forchette.


 Void posa_forchette(), Setto lo stato a PENSA e verifico se un filosofo ai miei lati può
mangiare in modo da rilasciare le bacchette.
Dall’algoritmo è possibile notare che ogni filosofo effettua solo una wait(forchetta[i])
ignorando la (i+1)esima che veniva effettuata nell’altra soluzione. Questo perché la rende
disponibile il filosofo adiacente quando esegue posa_forchette() dopo aver mangiato in
controlla_se_può_mangiare().

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

(qualora si fosse messo da solo in coda risveglia se stesso).


Posa(), setta lo stato a PENSARE e verifica i 2 filosofi adiacenti in modo da rendere
disponibili le risorse di destra e sinistra, in quanto Verifica() effettuerà alla fine la
signal(i+4)%5, (i+1)%5 rendendo disponibili le bacchette.
Questa soluzione è identica a quella semaforica con la differenza che la wait nel monitor
dipende dalla condizione stato(i)!=MANGIA. Inoltre essendo all’interno del monitor tutte le
procedure sono atomiche.

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

Barbiere Addormentato con Variabili di Condizione

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.

Caratterizzazione del deadlock


Un deadlock di risorsa avviene quando si verificano 4 condizioni:
1. Mutua esclusione, quando almeno una dellle risorse del sistema deve essere
acceduta in modo esclusivo.
2. Possesso e attesa, quando ad un processo vengono allocate delle risorse che continua
a tenere allocate poiché esso stesso è in attesa di altre risorse per poter completare le
proprie operazioni.
3. Nessuna prelazione, quando non si dà la possibilità alla CPU di prelazionare
forzatamente la risorsa allocata ad un processo per allocarla ad un altro.
4. Attesa circolare, quando si verifica una catena di processi ognuno dei quali attende
il rilascio di una risorsa da parte del processo che lo segue.
Le prime tre sono condizioni sufficienti ma non necessarie, l’ultima è una condizione
necessaria e sufficiente.

Risoluzione dei deadlock


Quando si verifica la 4 condizione si ottiene un deadlock conclamato.
Una volta che siamo in presenza di un deadlock conclamato le tecniche utilizzabili per la
risoluzione sono:
 Ferita, il kernel sottrae una risorsa alla volta al processo fino ad individuare quella
che libera dallo stallo;
 Morte, consiste nell’uccidere tutti i processi coinvolti in modo da liberare le risorse
allocate che andranno a soddisfare altre richieste.
Per poter risolvere una situazione di deadlock si può:
 Evitare il deadlock
 Prevenire il deadlock
 Ignorare il deadlock

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)

Algoritmo del Banchiere


L’algoritmo del banchiere è in grado di restituire un valore indicante uno stato sicuro o meno.
Stato sicuro: Si definisce uno stato sicuro uno stato in cui esiste almeno una sequenza
sicura di esecuzione di tutti i processi.
Richieste da prendere in considerazione:
1. quando un processo effettua una richiesta, si calcola il nuovo stato in cui si troverebbe
il sistema se la richiesta fosse ammessa. Chiameremo questo stato, stato proiettato;
2. se lo stato proiettato è uno stato sicuro, si ammette la richiesta aggiornando le matrici
Risorse_allocatee Risorse_totali; altrimenti, si tiene la richiesta in attesa;
3. quando un processo rilascia una o più risorse o termina la propria esecuzione, si
esaminano tutte le richieste in attesa e si allocano quelle che porterebbero il sistema
in un nuovo stato sicuro. Tutto ciò può essere realizzato usando un algoritmo di
individuazione dei deadlock, però apportando una modifica: il completamento di un
processo P, sia running che blocked, può richiedere (Risorse_massime -
Risorse_allocate) ulteriori unità di risorse di ogni classe di risorsa.
Quindi l'algoritmo controlla che per ogni classe di risorsa:
Risorse_totali - Risorse_totali_allocate  Risorse_massime(P) - Risorse_allocate(P. )
Se questa condizione è soddisfatta, viene simulato il completamento del processo P. E

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)

Un programma P scritto in linguaggio L prima di essere eseguito deve subire varie


trasformazioni. In particolare deve essere compilato  linkato  eseguito.
 Compilazione: durante la compilazione, le istruzioni del codice sorgente sono
tradotte in istruzioni macchina. Viene creato il modulo oggetto.
 Linking: durante la fase di linking, il codice delle librerie viene incluso nel modulo
oggetto. In pratica, vengono linkati al programma le funzioni che esso utilizzerà. Viene
creato il codice binario.
 Caricamento: durante il caricamento, il codice binario viene caricato in memoria per
poter essere eseguito dalla CPU.
Per fare riferimento ad un dato, ad un istruzione, ad un processo vengono assegnati degli
indirizzi in memoria.

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

Gestione a code separate

In questo approccio, ciascuna partizione ha una propria coda di


ingresso. All'avvio del sistema viene effettuata la suddivisione della
memoria in partizioni fisse.
Quando arriva un processo, viene messo nella coda di ingresso della
partizione più piccola che lo può contenere. Dal momento che le
partizioni sono fisse, in questo schema, tutto lo spazio di una
partizione non usato dal processo viene sprecato(frammentazione
interna). Lo svantaggio principale è che i piccoli processi devono
aspettare eventualmente anche una coda molto lunga per essere
inseriti in memoria, sebbene la maggior parte della stessa sia libera.

Gestione a coda unica


In questo approccio, tutte le partizioni hanno una singola coda di
ingresso "comune". La partizione della memoria viene sempre
effettuata all'avvio del sistema. Ogni qualvolta una partizione diventa
libera, vi viene caricato il processo più vicino alla testa della coda che
può entrare nella partizione, ed esso è quindi mandato in esecuzione.
Dal momento che non è desiderabile sprecare una partizione molto
grande per far girare un processo piccolo, un'altra strategia è quella

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

Gestione con bitmap


Con una Bitmap, la memoria viene divisa in unità di allocazione alle quali viene associato un
bit della mappa, che vale 0 se l'unità è libera e 1 se è occupata. Il problema principale, quando
si utilizza l'allocazione contigua, sta nel fatto che quando si decide di caricare
un processo di k unità il gestore della memoria deve esaminare la mappa di bit per trovare
una sequenza consecutiva di k zeri consecutivi. Questa è un'operazione lenta per cui le
bitmap sono poco utilizzate

Gestione con liste a puntatori


Quando si fa uso del partizionamento della memoria, il SO conserva una tabella nella quale
sono indicate le partizioni di memoria disponibili e quelle occupate. In pratica, il SO usa
questa tabella per tener traccia dello stato della memoria. Questa gestione della memoria è
chiamata gestione della memoria con liste concatenate. Inizialmente tutta la memoria è
a disposizione dei processi utente; si tratta di un grande blocco di memoria
disponibile, un buco. Ma col passare del tempo, vengono eseguiti molti processi, dunque,
solitamente, in memoria sono sparsi un insieme di buchi di diverse dimensioni.
Come detto, al tempo t esistono in memoria n buchi di differenti dimensioni. Quando un
processo è in attesa di memoria, esistono quattro tecniche per scegliere un buco libero tra
quelli disponibili:
 First-fit: questo è l'algoritmo più semplice nel quale si assegna al processo il primo
buco abbastanza grande da contenerlo a partire dall'inizio della lista. Quindi le

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

Allocatore Potenza del 2


Quando viene eseguita una richiesta per M byte, l'allocatore dapprima controlla la free list
contenente i blocchi la cui dimensione è 2I tale che 2I  M. Se questa free list è vuota,
controlla la lista contenente i blocchi con dimensione potenza del 2 successiva e così via. Un
intero blocco è allocato a una richiesta, ovvero non viene eseguita nessuna divisione dei
blocchi. Inoltre, non viene eseguita la fusione dei blocchi adiacenti per creare blocchi più
grandi; quando un blocco viene rilasciato, viene semplicemente restituito alla sua free list.

Allocazione della memoria


In passato, le vecchie architetture di computer utilizzavano l'allocazione contigua della
memoria. Nell'allocazione contigua della memoria, ciascun processo è contenuto in una
singola sezione contigua della memoria. Le moderne architetture di computer utilizzano il
modello di allocazione non contigua della memoria, in cui le varie parti di un processo
sono contenute in più aree di memoria, anche sparpagliate.

Allocazione non contigua


Esistono fondamentalmente due approcci per implementare l'allocazione non contigua della
memoria:
- paginazione , ogni processo viene diviso in parti di dimensione fissata, chiamate pagine
- segmentazione , un programmatore identifica le componenti di un processo chiamate
segmenti.

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.

Tabella delle pagine

La tabella delle pagine per ogni processo


contiene informazioni molto importanti come
ad esempio:
- il bit di validità, che indica se la pagina è
presente o meno in memoria (0 non presente -
1 presente)
- il #frame, che indica il frame di memoria
occupato dalla pagina
- il campo modificato, che indica se la pagina
è stata modificata o meno, cioè se è dirty; quando una pagina viene modificata (cioè è
dirty) deve essere copiata sul disco (page-out)
L’indirizzo base della tabella delle pagine è memorizzato in un registro detto: Page Table
Pointer poichè verrà acceduta in modo frequente e questo puntatore verrà poi utilizzato
durante la traduzione degli indirizzi da parte dell MMU.
Dato che le modern architetture supportano spazi di indirizzamento molto grandi (32 o 64
bit) ed ogni pagina ha una dimensione di pagina pari a 4KB cioè su di un architettura di 32
bit si ottiene una dimensione potenziale della tabella delle pagine pari a 2^20 elementi.
Essendo quindi la dimensione potenziale molto grande la tabella delle pagine non può
risiedere totalmente in memoria central.
Esistono due possibili approcci:
- Tabella delle pagine multilivello
- Tabella delle pagine invertita

76
Appunti di Sistemi Operativi Teoria

Tabella delle pagine multilivello


La tabella delle pagine multilivello consiste nel suddividere una tabella delle pagine, di
grosse dimensioni, in più livelli, evitando di tenere tutti i livelli in memoria per tutto il
tempo. In pratica, in questo modo, si effettua una paginazione della tabella dei processi: una
tabella delle pagine di alto livello viene utilizzata per accedere alle varie pagine della tabella
delle pagine. Se la tabella delle pagine di alto livello è grande, potrebbe essere essa stessa
paginata e così via.

Tabella delle pagine invertita


Invece di memorizzare in memoria centrale tutte le
pagine di un processo conservo solo le pagine che
sono effettivamente in memoria fisica. Quindi
conservo i frame in memoria fisica e la pagina
logica contenuta. In questo modo recupero dello
spazio ma si ha un problema riguardo la
conversione. Se abbiamo un processo N che si
riferisce alla pagina virtuale P, non possiamo
utilizzare più solo P come indice della tabella delle
pagine, ma devo ricercare la coppia (N,P) e questa
ricerca non viene fatta solo nel caso dei fault ma per ogni riferimento in memoria quindi vi è
una grossa complessità.
Dalla figura si vede come nella tabella delle pagine viene cercato sia il PID sia la pagina
Per evitare questo utilizziamo una tabella delle pagine di tipo hash in cui l'argomento della
funzione di hash rappresenta il numero della pagine virtuale

Tabella delle pagine hash


Per gestire le collisioni ogni
elemento della tabella di hash
contiene una lista concatenata di
elementi che la funzione hash fa
corrispondere alla stessa locazione.
La CPU genera per il processo un
indirizzo logico, il numero di pagina
viene passato alla funzione di hash
che identifica un elemento nella
tavola di hash. Questo elemento è un
puntatore a un elemento nella

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.

Dimensione ottimale delle pagine


La dimensione delle pagine è un parametro molto importante del sistema.
Se si usano pagine piccole si ha il vantaggio di avere uno spreco di memoria minore (a causa
dell'inutilizzo parziale dell'ultima pagina).
Se si usano pagine grandi si ha il vantaggio di avere tabelle delle pagine piccolo.
Siano:
- S la dimensione media dei processi
- P la dimensione delle pagine
- E la dimensione di un elemento nella tabella delle pagine
Allora:
- S/P sarà il numero di pagine in memoria
- SE/P sarà la dimensione della tabella
- P/2 sarà la memoria sprecata (è una stima)
Il costo sarà:
COSTO = SE/P + P/2
Derivando rispetto a P, si ottiene che la dimensione ottimale della pagina è:
P = sqrt (2SE)
Solitamente la dimensione delle pagine và da 1 KB a 64 KB.

Indirizzi della memoria


Abbiamo 2 tipi di indirizzi:
 Indirizzo logico, sono gli indirizzi usati dalla CPU per fare riferimento alla memoria
ed è un indirizzo intermedio.
 Indirizzo fisico, sono quegli indirizzi di memoria dove effettivamente risiede il dato o
l'istruzione. L'accesso alla memoria fisica avviene utilizzando gli indirizzi fisici.
La traduzione da indirizzi logici a fisici, attuata durante l'esecuzione dei programmi, viene
realizzata in hardware dalla MMU.
Il numero massimo di indirizzi possibili in memoria è detto Spazio di indirizzamento logico
e dipende dal numero di bit che costituiscono l’indirizzo, cioè se N è il numero di bit allora lo
spazio di indirizzamento lgico sarà 2^N.

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

TLB (Traslation Lookside Buffer)


Il TLB è detto anche memoria associativa, che è una memoria cache veloce contenuta nella
MMU che permette di velocizzare la traduzione degli indirizzi. Questo TLB contiene porzioni
della tabella delle pagine, cioè solo pochi elementi di quest'ultima. In particolare contiene gli
elementi che sono stati usati più di recente. Di ogni elemento memorizza alcune informazioni
principali come il numero il numero di pagina, il numero di frame e il campo per la
protezione (prot_info).
La dimensione delle memorie dei computer sono cresciute rapidamene dal 1990, le
dimensioni del TLB non sono andate di pari passo poiche sono costosi a causa della loro
natura associativa. Tipicamente la dimensione del TLB è piccola poiche costosa.
L’MMU prima di accedere direttamente alla tabella delle pagine cerca ala pagina prima nel
TLB quindi le eventualità sono due:
• trova la pagina nel TLB (hitratio). In tal caso recupera il numero di frame, lo
sostituisce al numero di pagina e aggiungendoci l'offset ottiene direttamente
l'indirizzo fisico
• non trova la pagina nel TLB(missratio), allora la ricerca nella tabella delle pagine.
Una volta trovata sostituisce il numero di frame al numero di pagina e ci aggiunge
l'offset
• non trova la pagina neanche nella tabella delle pagine e viene generato un
pagefault

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

PR1 x 2Tmem +(1-PR1) x(Tmem + Tpf + 2Tmem)

 PR1 è la probabilità di hitratio, cioè la probabilità di trovare la pagina in memoria


principale e quindi la probabilità di NON avere pagefault
 Tmem è il tempo di accesso alla memoria principale
 1-PR1 è la probabilità dell'evento opposto a hitratio (missratio). Rappresenta la
probabilità di non trovare la pagina in memoria centrale ed è quindi necessario
caricarla dalla secondaria
 TPF è il tempo di gestione del pagefault (quindi overhead) Quando l'indirizzo è in
memoria centrale allora il tempo totale è solo 2xTmem perchè dobbiamo solo accedere
alla memoria, due volte perchè una per costruire l'indirizzo e l'altra per farvi
riferimento.

Seconda formula con TLB

PR2 *(Ttlb+Tmem)+(PR1-PR2)x(Ttlb+2Tmem)+
+ (1-PR1) x (Ttlb+Tmem+Tpf+Ttlb+2Tmem)

 PR2 è la probabilità che un pagina esista nel TLB (hitratio)


 Ttlb è il tempo di accesso al TLB
 PR1-PR2 è la probabilità che la pagina non è nel TLB ma in memoria centrale, il non
trovarla nel TLB sarebbe uguale a -PR2
 1-PR1 è la probabilità di non trovare la pagina in memoria centrale e quindi caricarla
dalla memoria secondaria
Inizialmente voglio trovare la pagina nel TLB, moltiplico questa probabilità di trovarla con
Ttlb+Tmem, ovvero sela pagina è presente nel TLB avrò un tempo di ricerca Ttlb e poi creo
l'indirizzo fisico e faccio riferimento alla memoria con un tempo Tmem. Se invece non la trovo
nel TLB e voglio cercarla in memoria con una probabilità pari a PR1-PR2 avrò un primo
accesso al TLB con insuccesso e 2 accessi alla memoria uno per comporre l'indirizzo fisico e
l'altro per farci riferimento (Ttlb+2Tmem). Se non la trovo nemmeno in memoria centrale, con
una probabilità di 1-PR1 dovrò generare un pagefault per caricarla dalla memoria

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) + (PR1-PR2) * (Ttlb+ 2Tmem)+


+ (1-PR1)*%D_0*(Ttlb+Tmem+Tpf+Ttlb+2Tmem)+
+ (1-PR1)* %D_1 * (Ttlb+Tmem+Tpf+Tswap+Ttlb+2Tmem).

 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.

Sostituzione delle pagine


Nel caso in cui si vuole fare accesso ad una pagina di un processo non caricata in memoria
central, bisogna cercarla nell’area di swap del disco e quindi effettuare quello che viene
chiamato page-in. Ora gli scenari sono due:
 O in memoria abbiamo almeno un frame libero, in questo caso l’MMU effettua lo swap-
in della pagina dall’area di swap del disco in memoria centrale

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

La sostituzione ottimale consiste


nel sostituire le pagine in modo tale
che il numero totale di page fault
durante l'esecuzione di un processo
sia il minimo possibile. Vengono
sostituite solo quelle pagine che non
si useranno per il periodo di tempo più lungo, ma risulta inutilizzabile poichè il problema
risiede nell’individuazione della pagina vittima poichè dovremmo conoscere il futuro. Viene
utilizzata come riferimento per le altre strategie, cioè tanto più un altra strategia si avvicina
a questa come funzionamento tanto più è valutata efficiente.

Algoritmo FIFO

La politica di sostituzione delle


pagine FIFO, ad ogni page fault,
sostituisce la pagina che è stata
caricata in memoria prima di ogni
altra pagina del processo, cioè quella
che risiede in memoria da più
tempo. In pratica, il SO mantiene una lista di tutte le pagine correntemente in memoria,
dove la pagina di testa è la più vecchia e la pagina in coda è quella arrivata più di recente. Al
momento del page fault, la pagina in testa viene rimossa anche se è la pagina più utilizzata,

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.

Algoritmo NRU (Not Recently Used)


La maggior parte dei computer con memoria virtuale prevede due bit per la raccolta di
informazioni sull’utilizzo delle pagine:
 Un bit R che indica se la pagina è stata Referenziata
 Un bit M che indica se la pagina è stata Modificata
Inizialmente entrambi I bit vengono settati a 0.
Quando avviene un page fault il Sistema Operativo controlla tutte le pagine e le divide in
classi a seconda del valore dei bit precedent:
 Classe 0, (R = 0, M = 0)
 Classe 1, (R = 0, M = 1), è possibile resettare il bit di riferimento mentre lasciamo M=1
 Classe 2, (R = 1, M = 0)
 Classe 3, (R = 1, M = 1)
L’Algoritmo NRU rimuove una pagina qualsiasi da una classe partendo dal numero inferiore
a patto che sia non vuota. Quindi cerca di rendere vittima inizialmente una pagina che non
è stata ne referenziata ne modificata e poi il resto.

Allocazione Frame ai processi


Unix
Unix utilizza un allocazione dei frame ai processi Variabile in ambito Globale, cioè la pagina
vittima viene cercata tra tutti i frame allocate a tutti i processi infatti I frame liberi sono
organizzati in una lista globale.
In caso di page fault al processo viene assegnato un frame libero indipendentemente dalla
sua attuale dimensione fisica. Se la lista si esaurisce la scelta di quale processo penalizzare
può essere arbitraria.

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.

Il modello a Working Set


La maggior parte dei processi esibiscono la localita di riferimenti cioè un processo non fa
riferimento a tutte le pagine ma solo ad una piccolo insieme di esse. Cioè se un processo sta
eseguendo codice di un programma principale il quale occupa determinate pagine il processo
farà continuo riferimento a quelle pagine fin quando non effettuerà una chiamata esterna
che lo faccia uscire dalle pagine che stave utilizzando.
L’insieme delle pagine che un processo sta correntemente utilizzando viene chiamato:
working set (insieme di lavoro). Più è alto il numero di pagine presenti in memoria e più è
alta la probabilità che tutto il working set di un processo sia interamente in memoria e che
quindi non si abbiano page fault. Un programma che causa page fault per ogni piccolo
insieme di istruzioni viene detto in Trashing.
La determinazione della dimensione dell’insieme dei frame assegnati ad un processo si basa
sull’andamento del working set cioè si controlla la variazione della dimensione del working
set. Periodicamente si rimuovono dal working set le pagine non utilizzate, quando l’insieme
dei frame allocati è minore del working set vengono allocati ulteriori frame, se invece la
dimensione del working set aumenta significa che sono necessari un numero maggiore di
frame. Per questo motivo il numero di frame allocati segue l’andamento del working set.
Dato t unità di tempo, Delta il numero di pagine
utilizzate da un dato processo indichiamo con W(
Delta,t) il working set di un determinate processo
nell’istante di tempo indicato con t. Se tracciamo su un
asce delle ascisse il Delta e sull’ asse delle ordinate
osserviamo che la funzione che rappresenta il Delta è una funzione non decrescente.

89
Appunti di Sistemi Operativi Teoria

Il funzionamento del WS ha una variazione prevedibile, cioè:


 Aumenta all’inizio dell’esecuzione, poi si stabilizza per il principio di località
 Cresce nuovamente quando il processo sposta il proprio indirizzamento verso un
altro ambito di località
 Raggiunge un massimo quando contiene pagine che appartengono alle due località
 Decresce quando si stabilizza nel nuovo ambito di località
La proprietà di cui gode il WS è che per finestre temporali crescent il WS aumenta

cioè, se ad un istante t verifico la localita di riferimenti ottendendo Delta questo sarà un


sottoinsieme del WS che vengono riferite nel Delta + 1 unità di tempo. Vi è anche una
limitazione nella dimensione del WS, cioè il minimo numero di pagine di un WS è 1 mentre
il Massimo numero di pagine di un WS è il minimo tra la dimensione di Delta (finestra
temporale dei riferimenti) e il numero totale di pagine necessarie al processo (N).
Per osservare la dimensione del WS si osservano I page fault

Algoritmo Page Fault Frequency


L’algoritmo PFF si basa sulla considerazione che per la maggior parte degli algoritmi la
frequenza di Page Fault decresce all’aumentare del numero di pagine assegnate.
Cerca di mantenere la frequenza dei Page-Fault all’interno di un intervallo ragionevole e si
determinano in modo prefissato due soglie (una superiore e una inferiore) in modo tale da
cercare di mantenere I page fault all’interno di queste due soglie.

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

Allocazione della memoria del kernel


Casi studio
Gestione della memoria in Unix
In unix viene gestita la memoria mediante:
 Paginazione
 Allocazione di memoria per il kernel (luzy buddy)

Allocatore Lazy Buddy (utilizzato da Unix)


L’allocatore lazy buddy viene utilizzato in Unix 5.4 e tende a ritardare quelle che sono le
operazioni di fusione dei blocchi liberi poichè verosimilmente dovranno poi essere ridivisi.
Funzionamento:
I blocchi con la stessa dimensione sono considerati parte di una classe di blocchi.
L’allocatore caratterizza il comportamento del SO rispetto ad una classe di blocchi in tre stati
chiamati: lazy, reclaiming e accelerated.
 Nello stato lazy le operazioni di divisioni e fusion avvengono con un ciclo stabile e
quindi potenzialmente inutili. Come rimedio le fusioni e le divisioni eccessive possono
essere entrambe evitate ritardando la fusione.
 Nello stato reclaiming I rilasci si verificano piu frequentemente rispetto alle allocazioni
per cui risulta una buona idea fondere I blocchi ad ogni rilascio.
 Nello stato accelerated I rilasci si verificano ancora piu velocemente rispetto alle
allocazioni per cui è auspicabile fondere ad un tasso ancora più elevato.
L’implementazione in Unix usa due tipi di blocchi. I blocchi piccoli variano in dimensione tra
8 e 256 byte mentre quelli grandi tra 512 e 16Kb. L’allocatore ottiene memoria dal sistema
di paginazione in aree di 4KB. In ogni area crea un pool di blocchi e una bitmap per tenere
traccia dello stato di allocazione dei blocchi. Quando tutti I blocchi nel pool sono liberim
restituisce l’area al Sistema di paginazione.

Gestione della memoria in Linux


Linux utilizza una dimensione della pagina di 4KB. Su un architettura a 64 bit usa una
tabella delle pagine a tre livelli (page global directory, page middle directory e tabella delle
pagine) e di conseguenza un indirizzo logico consta di 4 parti: 3 per I tre livelli e il 4 per il
numero di byte della pagina.
La sostituzione di pagina in Linux si basa sull’algoritmo di clock. Il kernel tenta di tenere
sempre un numero dufficiente di frame liberi in modo che I page-fault possono essere
rapidamente gestiti usando uno dei frame liberi. Usa delle liste chiamate: lista attiva e lista
inattiva e tiene la dimensione della lista attiva ai due terzi della lista inattiva. Quando il

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.

Gestione della memoria in Windows


Windows supporta gli indirizzi logici sia a 32 bit che a 64. La dimensione di pagina è 4KB
mentre lo spazio di indirizzamento di un processo è 2GB o 3GB il resto dello spazio di
indirizzamento logico è riservato al SO dove viene allocato il kernel. Windows usa una tabella
delle pagine a 2,3 o 4 livelli. La tabella delle pagine di piu alto livello è detta page directory
(PD) che contiene 1024 entry di 4byte ciascuna. Ogni entry della PD punta alla tabella delle
pagine (PT). Ogni PT contiene 1024 entry di 4byte ciascuna. Un indirizzo logico è diviso in 3
parti:

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

 Posizione sul disco


 Protezione

Operazioni sui file


Le operazioni che generalmente si possono effettuare sui file sono:
 Apertura
 Chiusura
 Copia
 Cancellazione
 Lettura/scrittura
 Ridenominazione

Tipologie di accesso ai file


Esistono diversi modi per poter accedere ad un file:
Pila
I record sono salvati nell'ordine di arrivo, i campi possono essere diversi
tra loro per questo motivo ogni campo in un record deve avere un nome
e un valore. La lunghezza di ogni campo deve essere descritta con un
sottocampo oppure con dei delimitatori. L'accesso ai record quindi viene
fatto tramite una ricerca esaustiva. Si utilizza quando i dati vengono
collezionati prima di un elaborazione o quando sono difficili da
organizzare. Questo tipo di file è adatto per ricerche complete ed è molto
facile da aggiornare

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.

File sequenziale indicizzato


E’ sequenziale perchè conserva la caratteristica di avere un campo chiave per ogni record.
Inoltre ci sono due importanti caratteristiche: un indice di file che supporta l'accesso casuale
e un file di overflow. L'indice è una funzionalità di ricerca che permette di raggiungere
facilmente un record ricercato arrivando nelle vicinanze di esso senza scorrere tutto il file in

98
Appunti di Sistemi Operativi Teoria

maniera sequenziale. Si tratta un file sequenziale


che ha due campi, un campo chiave (uguale a quello
del file principale) e un puntatore al file principale.
Quando si fa una ricerca io consulto il file indice e
cerco un elemento (dal campo chiave) che sia uguale
o immediatamente precedente a quello desiderato,
una volta trovato uso il puntatore per accedere al file
principale o al file di overflow. Il file di overflow ha
un funzionamento simile a quello del log, quando
vogliamo aggiungere un nuovo record al file
principale questo viene inserito nel file overflow e al
suo record immediatamente precedente (che può
essere in principale o anch'esso in overflow) aggiorno il puntatore in modo che punti al nuovo
record. Ogni record del file principale ovviamente avrà un campo puntatore al file di overflow.
In generale quindi un record o è in memoria principale e ci accedo direttamente tramite
l'indice o è in overflow e ci accedo tramite il puntatore del campo del record presente in
memoria principale. Periodicamente i due file vengono uniti e quindi si aggiorna il file
principale. Il motivo per cui è più efficiente la tabella indice si spiega con questo esempio:
Supponiamo di avere 1000 record, se faccio una ricerca sequenziale ottengo il risultato in
media dopo 500 accessi. Se invece ho un indice di 10 ingressi, cioè suddivido il file principale
in 10 blocchi da 100 elementi ciascuno. Eseguo in media 5 accessi nell'indice per ottenere
il mio blocco e poi altri 50 tra quelli nel file principale. Quindi 55 invece di 500. Per aumentare
l'efficienza posso usare anche livelli multipli di indicizzazione cioè fare indici di indici

File diretto o Hash


Sfrutta la capacità dei dischi di accedere direttamente ad ogni
blocco di cui conosco l'indirizzo. Ogni record contiene un campo
chiave sul quale è usata una tecnica di hashing e un altro campo
puntatore al file di overflow nel caso di ricerca prima che venga
effettuato il merge tra i due file. E' necessario gestire
opportunamente le collisioni.

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.

Metodi di organizzazione dei blocchi


Organizzazione a blocchi fissa
Si usano record a dimensione fissa e in un blocco possono entrare solo un numero intero di
record. Quando un record
termina, il successivo non viene
inserito se non c'è spazio per
contenerlo tutto. Come si vede
dalla figura la parte grigliata rappresenta la frammentazione interna, cioè spazio allocato ma
non utilizzato che in questo caso è dovuto, per definizione al vincolo dell'ampiezza del blocco
rispetto all'ampiezza del record. I quadratini all'inizio e a metà sono buchi dovuti alla
progettazione hardware del blocco

Organizzazione a blocchi variabili senza riporto

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.

Organizzazione a blocchi variabili con riporto

Usiamo record a lunghezza variabile e


usiamo il riporto ovvero mettere a cavallo
tra due blocchi. Il riporto si può usare sia
tra due blocchi della stessa traccia (prima
figura) che tra due tracce consecutive (seconda figura). E' vero che con questo metodo
riduciamo lo spreco di spazio, però aggiungiamo un puntatore perchè quando si fa
l'accavallamento il primo pezzo del record deve avere un puntatore per sapere dov'è il
secondo pezzo.

100
Appunti di Sistemi Operativi Teoria

Metodi di allocazione dei file


Allocazione contigua
I primi file system usavano il modello di allocazione contigua della memoria, cioè
allocavano una singola area di memoria a ogni file al momento della creazione. In questa
allocazione ogni file occupa un insieme di blocchi contigui sul disco, quindi questa
allocazione risulta essere particolarmente semplice poiché basta conoscere il blocco iniziale
e la lunghezza del file. Questa allocazione porta però alla frammentazione esterna, cioè si
hanno area di memoria troppo piccole per poter essere riutilizzate; ma portava anche alla
frammentazione interna poiché il file system era progettato per allocare spazio extra sul disco
per consentire al file di crescere.

Allocazione non contigua


I moderni file system adottano l'allocazione non contigua della memoria per l'allocazione
dello spazio sul disco. L'allocazione non contigua può essere concatenata o indicizzata.

Allocazione concatenata

L'allocazione concatenata risolve il problema della frammentazione esterna e quello della


dichiarazione delle dimensioni del file, entrambi presenti nell'allocazione contigua della
memoria. Tuttavia, in mancanza di una FAT, l'assegnazione concatenata non è in grado di
sostenere un efficiente accesso diretto, poiché i puntatori ai blocchi sono sparsi, con i blocchi
stessi, per tutto il disco e si devono recuperare in ordine.
In questa allocazione, ogni file è rappresentato da una lista concatenata di blocchi del disco,
che possono essere sparpagliati ovunque sul disco.
Ogni blocco del disco ha due campi al suo interno:
- dati, che contiene, appunto, i dati
- metadati, che è un campo di tipo link e punta al prossimo blocco
Il campo Info_di_posizione dell'elemento della directory punta al primo blocco sul disco del
file. Agli altri blocchi si accede seguendo i puntatori dei vari blocchi. L'ultimo blocco del disco
contiene un informazione null nel campo metadati. Lo spazio libero sul disco è rappresentato
da una free list in cui ogni blocco libero contiene un puntatore al successivo. Quando viene
richiesto un blocco, viene estratto un blocco dalla free list per poi essere aggiunto alla lista

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.

File allocation table (FAT)

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

L'allocazione indicizzata risolve il problema dell'accesso diretto, presente nell'allocazione


concatenata, raggruppando tutti i puntatori in una sola locazione: il blocco indice.
Nell'allocazione indicizzata si mantengono tutti i puntatori ai blocchi di un file in una tabella
indice chiamata file map table (FMT). In questa tabella sono riportati gli indirizzi dei blocchi
del disco allocati a un file. Ogni file ha il proprio blocco indice (o tabella indice): nella sua
forma più semplice, un FMT è un array di indirizzi di blocchi del disco. Ogni blocco ha un
solo campo, il campo dati. L'i-esimo elemento del blocco indice punta all'i-esimo blocco del
file. Il campo Info_di_posizione dell'elemento della directory relativo a un file contiene
l'indirizzo della FMT, cioè punta alla FMT. Una volta creato il file, tutti i puntatori del blocco
indice sono impostati a null. Quando le dimensioni del file crescono, viene localizzato un
blocco libero e l'indirizzo di questo blocco viene aggiunto alla FMT del file.
VANTAGGI:
 Questa allocazione permette di accedere direttamente a un blocco del file direttamente
dalla FMT senza avere frammentazione esterna. Inoltre l'affidabilità è migliore in

103
Appunti di Sistemi Operativi Teoria

quanto il danneggiamento di un elemento della FMT non compromette l'intero file, ma


solo una parte di esso.
SVANTAGGI:
 Il problema principale consiste nella dimensione del blocco indice, cioè della FMT. Se
essa è troppo piccola non può contenere un numero di puntatori sufficiente per un
file di grandi dimensioni, quindi è necessario disporre di un meccanismo per gestire
questa situazione.

INDICE A PIU' LIVELLI


Una prima soluzione consiste nell'utilizzo di un blocco indice a più livelli.
In questa organizzazione, ogni elemento della FMT
contiene l'indirizzo di un blocco indice. Un blocco indice
non contiene dati; contiene elementi che contengono gli
indirizzi dei blocchi dati. Per accedere ai blocchi dati,
prima accediamo a un elemento della FMT e otteniamo
l'indirizzo di un blocco indice.
Successivamente, accediamo a un elemento del blocco
indice per ottenere l'indirizzo di un blocco dati.

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

File System in Unix


I-NODE
Le informazioni che costituiscono l'elemento della directory relativo a un file (nome, tipo,
dimensione, locazione, protezione, open count, lock, flag, Misc Info), in Unix, sono divise tra
l'elemento della directory e l'i-node del file. L'elemento della directory contiene solo il nome e
il numero di inode; la maggior parte delle informazioni di un file è contenuta nel suo inode.
Quindi, un file in Unix è rappresentato da un inode (nodo indice). In Unix, l'amministratore
di sistema può specificare una quota disco per ogni utente. Questo impedisce a un utente di
occupare uno spazio elevato su disco rigido oppure tutto lo spazio disponibile. La struttura
dati inode viene mantenuta sul disco. Essa contiene le seguenti informazioni:
 Tipo di file (directory, link o file speciale)
 Numero di link al file
 Dimensione del file
 ID del dispositivo su cui è memorizzato il file
 Numero seriale dell'inode
 ID utente e gruppo del proprietario - Permessi di accesso
 Informazione sull'allocazione
La divisione dell'elemento della directory tra l'elemento della directory e l'inode facilita la
cancellazione dei link. Un file può essere cancellato quando il suo numero di link va a zero.
Unix utilizza l'allocazione indicizzata dello spazio su disco, con dimensione del blocco di
4KB.
Ogni file ha una FAT memorizzata nel proprio inode. Infatti gli inode contengono, oltre agli
attributi elencati in precedenza, altri 15 elementi, di cui 12 sono indirizzi diretti e 3 sono
indirizzi indiretti. Questi ultimi vengono allocati su richiesta, cioè quando servono
effettivamente.
 i primi 12 puntano direttamente ai blocchi dati del file
 gli altri 3 puntano a blocchi indice, in particolare o il 13° punta a un blocco indiretto
di primo livello, cioè un blocco che contiene puntatori a blocchi datio il 14° punta a
un blocco indiretto di secondo livello o il 15° punta a un blocco indiretto di terzo livello
(non viene quasi mai usato)
In questo modo la dimensione totale del file può arrivare a un massimo di 2^42 byte. Ma,
visto che gli indirizzi sono a 32 bit, la dimensione di un file è limitata a 2^32-1 byte. Il
numero di indirizzi contenuti in ogni blocco indiretto dipende dalla dimensione dei singoli
blocchi e dalla dimensione degli indirizzi. In Unix, la dimensione comune dei blocchi è 4KB,
mentre gli indirizzi sono di 32.

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).

Struttura a due livelli

Questa struttura presenta due tipi di directory:


 la directory master contiene informazioni relative alle directory utente di tutti gli
utenti del sistema; ogni elemento di un directory master è una coppia che consiste di
un ID utente e di un puntatore a una directory utente
 una directory utente (UD) contiene elementi che descrivono i file appartenenti a un
utente. Questa soluzione richiede che i nomi siano unici solo all'interno dell'area del
singolo utente. Infatti l'uso di UD separate permette la libertà nell'assegnazione di un
nome ad un file, infatti la figura mostra che vi sono più file con lo stesso nome (beta).
Una tale organizzazione garantisce l'accesso al file corretto anche se nel sistema

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.

Affidabilità del file system


L'affidabilità del file system è il grado di funzionamento corretto di un file system, anche
quando si verificano malfunzionamenti come la corruzione dei dati nei blocchi del disco e
fault di sistema dovuti a interruzioni di corrente.
I due aspetti principali dell'affidabilità del file system sono:
 garantire la correttezza della creazione, cancellazione e aggiornamento dei file
 prevenire la perdita dei dati contenuti nei file
Quando si parla di affidabilità bisogna tenere conto del fault (o guasto) e del failure (o
insuccesso). Un fault è un difetto in qualche parte del sistema. Un failure è un
comportamento erroneo, o che differisce dal comportamento atteso. L'occorrenza di un fault

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

"muoversi" sul piatto grazie al braccio in modo tale da scorrere le tracce.


Riassumiamo schematicamente le parti essenziali di un disco:
 Piatto - un disco rigido si compone di uno o più dischi paralleli, di cui ogni superficie,
detta piatto, è identificata da un numero univoco ed è destinata alla memorizzazione
dei dati
 Traccia - Ogni piatto si compone di numerosi anelli concentrici numerati, detti tracce,
ciascuna identificata da un numero univoco
 Cilindro - L'insieme di tracce alla stessa distanza dal centro presenti su tutti i dischi
è detto cilindro.Corrisponde a tutte le tracce aventi il medesimo numero, ma diverso
piatto
 Settore - Ogni piatto è suddiviso in settori circolari, ovvero in spicchi radiali uguali
ciascuno identificato da un numero univoco
 Blocco - L'insieme di settori posti nella stessa posizione in tutti i piatti
 Testina - Su ogni piatto è presente una testina per accedere in scrittura o in lettura
ai datimemorizzati sul piatto; la posizione di tale testina è solidale con tutte le altre
sugli altri piatti. In altre parole, se una testina è posizionata sopra una traccia, tutte
le testine saranno posizionate nel cilindro a cui la traccia appartiene

Parametri di prestazioni del disco


Analizziamo le prestazioni del disco. Uno dei parametri più importanti è il tempo di accesso,
ovvero l'intervallo di tempo tra l'esecuzione di un comando di lettura o scrittura e l'inizio del
trasferimento dei dati.Il tempo di accesso per un record di un disco è dato da:
TA = Ts + Tr + Tt

 Ts è il tempo di ricerca (o tempo di seek), cioè il tempo necessario per muovere la


testina sulla traccia desiderata (valori soliti 5-15ms).
 Tr è la latenza rotazionale, cioè il tempo impiegato dal disco per ruotare portando il
settore interessato sotto la testina richiesta; la latenza rotazionale media è il tempo
impiegato per mezza rivoluzione del disco (valore soliti 3-4ms).
 Tt è il tempo di trasferimento (o transfer rate), cioè il tempo necessario per trasferire
un numero di blocchi (o settori) da leggere/scrivere (valori soliti decine di megabyte al
secondo).
Tr è dato da 1/r dove r è la velocità di rotazione.
Tt è dato da b/rn dove b è il numero di blocchi da trasferire, r è la velocità di rotazione e n è
il numero di blocchi per traccia.

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.

MTTF = MTTFdisco\Numero dei dischi

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.

MTTF = (MTTFdisco)^2 \(2 * Numerodischi * MTTR)


MTTR: Mean Time To Repair

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.

MTTF = (MTTFdisco)^2 \ (Numerodischi*(Numerodischi – 1) * MTTR)

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

MTTF = (MTTFdisco)^2 \ (Numerodischi * (Numerodischi – 1) * MTTR)

VANTAGGI:
 Possono essere effettuate più operazioni di I/O contemporaneamente se le operazioni

114
Appunti di Sistemi Operativi Teoria

di lettura sono piccole.


 Affidabilità molto alta.
 Un solo disco viene utilizzato per memorizzare i codici per la correzione degli errori.
SVANTAGGI:
 C'è la possibilità di effettuare una sola operazione di scrittura alla volta, sia se
l'operazione di scrittura è grande, sia se piccola.
 Il disco di parità è un collo di bottiglia in quanto l'operazione di scrittura impedisce al
sistema di effettuare operazioni in parallelo

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

Scheduling del disco


First come first served (FCFS)
Seleziona l'operazione di I/O con tempo di richiesta inferiore, cioè le richieste vengono servite
in modo sequenziale, in base all'ordine di arrivo.

Shortest seek time first (SSTF)


Seleziona l'operazione di I/O con il più breve tempo di ricerca rispetto alla posizione corrente
delle testine del disco, cioè seleziona la richiesta che richiede il minor movimento della testina
dalla sua posizione corrente.

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.

Obiettivi della sicurezza e della protezione


Gli obiettivi della sicurezza sono 4:
 Segretezza, cioè solo gli utenti autorizzati hanno accesso alle informazioni. Questo
obiettivo è anche detto confidenzialità
 Privatezza, Le informazioni sono usate solo per gli scopi per I quali erano state intese
e condivise.
 Autenticità, è possibile appurare la sorgente o il mittende dell’informazione e
verificare inoltre che l’informazione è stata conservata nella forma in cui era stata
create.
 Integrità, mantenere intatte le informazioni
Solo la privatezza è un element esclusivamente legato alla Protezione, I restanti riguardano
sia la Protezione che la Sicurezza.

Attacchi alla sicurezza


Gli attacchi alla sicurezza più comuni sono due:
 impersonificazione (masquerading): assumere l'identità di un utente registrato del
sistema attraverso strumenti illegittimi.
 denial of service (DoS): impedire che gli utenti registrati del sistema accedano alle
risorse per cui posseggono i privilegi di accesso.
In un attacco di impersonificazione, concluso con successo, l'intruso ottiene l'accesso alle
risorse alle quali è autorizzato l'utente che sta impersonando, di conseguenza può modificare
o distruggere programmi e dati appartenenti ad esso. Consiste essenzialmente
nell'attivazione di programmi, come trojan, virus e worm, costituiti da codice "infetto".
Un attacco di tipo DoS, è lanciato sfruttando i bug del SO, in particolare i bug riguardanti la
sua progettazione e il suo funzionamento. In pratica è una tecnica per tempestare di richieste
un singolo servizio al fine di farlo collassare.

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.

La funzione Feistel (F)


La funzione Feistel, rappresentata nella Figura 2, opera su mezzo blocco (32 bit) per volta e
consiste di 4 passi:
 Espansione - il mezzo blocco di 32 bit è espanso fino a 48 bit duplicando alcuni bit.
 Miscelazione con la chiave - il risultato è combinato con una sottochiave usando
un'operazione di XOR.
 Sostituzione - dopo la miscelazione con la sottochiave, il blocco viene diviso in 8 parti
di 6 bit prima del processamento con le S-box (scatole di sostituzione). Ognuna delle
8 S-box sostituisce 6 bit in input con 4 bit in output mediante una trasformazione
non lineare effettuata mediante una tabella.
 Permutazione - infine, i 32 bit risultanti dalle S-box sono riordinati in base alle
permutazioni fisse della P-box o permutation box.

122
Appunti di Sistemi Operativi Teoria

Gestore della chiave


Inizialmente, vengono selezionati 56 bit della chiave dagli
iniziali 64 bit. I rimanenti 8 bit sono scartati o utilizzati
come bit di controllo della parità. I 56 vengono poi suddivisi
in 2 metà di 28 bit; ogni metà è poi
trattata separatamente. Nei cicli
successivi entrambe le metà vengono
fatte slittare verso sinistra di 1 o 2 bit
e quindi vengono scelti 48 bit per la
sottochiave( 24 bit dalla metà di
sinistra e 24 bit da quella di destra)

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

Algoritmo dello zaino


Abbiamo n oggetti ed uno zaino, l’obiettivo del problema dello zaino è rendere più profiquo
possibile il riempimento dello zaino con gli oggetti interi. Esiste anche un altra versione del
problema dello zaino (zaino frazionario) dove è possibile inserire anche una porzione di
oggetto. Nello scenario della cifratura non abbiamo la capienza ne il valore, abbiamo un
messaggio da cifrare compost da una stringa binaria e dei pesi noti a priori. Lo zaino viene
riempito di volta in volta per questo motive non vi è capienza iniziale.
Cioè definiti:
 W la capienza, (testo cifrato)
 Mi i pesi (chiave pubblica)
 Bi,i bit di informazione della stringa da cifrare

∑𝑛𝑖=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

Matrice di controllo degli accessi (ACM)


Una matrice di controllo degli accessi
(ACM) è una struttura di protezione che
fornisce accesso efficiente sia ai privilegi
di accesso degli utenti ai vari file sia alle
informazioni per il controllo degli accessi
ai file. Ogni elemento dell'ACM contiene i privilegi di accesso di un utente a un file. Ogni
utente ha una riga nell'ACM, mentre ogni file ha una colonna. In questo modo, una riga
nell'ACM descrive i privilegi di accesso di un utente per tutti i file nel sistema, ed ogni colonna
descrive le informazioni per il controllo degli accessi a un file. La matrice risulta essere di
grandi dimensioni perché solitamente un SO contiene molti utenti e un numero elevato di
file

Liste di controllo degli accessi (ACL)


La lista di controllo degli accessi (ACL) di un file è
una rappresentazione delle informazioni per il
controllo degli accessi; contiene gli elementi non
nulli relativi alla colonna del file nell'ACM.
Un L'ACL elimina la necessità di memorizzare i privilegi di accesso nulli, ma nonostante ciò,
la presenza di un gran numero di utenti in un sistema comporta ACL di grandi dimensioni,
e pertanto uno spreco di spazio. L’ ACL è memorizzata come una lista di coppie del tipo
(ID_utente, privilegi_di_accesso).

Capability list (C-list)


Una capability list (C-list) rappresenta i privilegi di accesso di un
utente a vari file nel sistema; essa contiene le entry, non nulle, che
avrebbe contenuto la riga dell'utente nell'ACM. Ogni entry nella C-
list è una capability, che rappresenta i privilegi di accesso ad un file;
è costituita da una coppia del tipo (file_ID, privilegi_di_accesso). Le C-list sono solitamente di
piccole dimensioni.

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.

Possibili Domande all’orale


- come si crea un processo?
- cos'è un compilatore?
- cosa fa la TRAP?
- Come avviene il passaggio da modalità utente a modalità Kernel?
- Chi intercetta gli interrupt?
- Cos'è il DMA?Come funziona?
- Chi parla con il DMA?
- Cos'è il Driver di dispositivo?
- Stati dei Processi
- Cos' è l'I/O Bound
- cos'è un processo
- Cosa abbiamo all'interno di un processo?
- Dove si trova il kernel?
- Pipe e Pipe Fifo
- Differenza tra DMA break point ed interrupt
- Funzione fstat
- Raid 5
- Thread Kernel e User
- TLB Thread Kernel e User dove sono?
- Wait e Signal
- Variabili di condizione
- Overhead
- Throughput, come si calcola?
- Context Switch, cos'è il contesto?
- PCB
- Protezione
- read,write,open (vuole sapere come il s operativo gestisce la chiamata di sistema, tutti i
passi della kiamata di sistema fino alla read write ecc)
- semafori e variabili di condizione, differenze
- quali criteri devono essere soddisfatti?

130
Appunti di Sistemi Operativi Teoria

- cosa dice l attesa limitata?cosa bisgna garantire


- quali, tra le soluzioni che conosci, garantisce il rispetto di queste condizioni?(semafori)
- la mutua escusione è sempre garantita con l utilizzo dei semafori?(dipende dal tipo di
semaforo)
- se il semaforo è inizializzato ad N quanti processi possono entrare in sezione critica? (n-
1)
- perchè è garantita l attesa limitata?
- perchè è garantito il progresso?
- funziona anke su sistemi multiprocessore?(si perchè la memoria è condivisa)
- RSA (spiegazione algoritmo)
- cos è un superblocco?
- perchè parliamo di grafi aciclici invece che di alberi? (poike esistono link tra un nodo e
ogni altro nodo)
- Come funzionano le system call
- Prototipo della waitpid
- Cos'è un processo zombie
- Cosa si intende per sicurezza e cosa per protezione?
- Cos'è una capability?
- Come funzionano i meccanismi di sicurezza sotto Windows?
- Paginazione
- Dove risiedono i processi utente (area kernel o area utente?)
- Dove risiede il kernel?
- Il kernel può essere paginato?
- Come funziona il buddy system?
- Scrivere un programma che richiama una funzione per calcolare il minimo contenuta in
un file esterno
- Da cosa è limitato lo spazio di indirizzamento logico di un programma e da cosa è limitato
lo spazio di indirizzamento fisico di un programma?
- Cos'è il segmentation fault?
- Si può disabilitare il dump del disco?
- Quali condizioni si devono verificare per far sì che nel sistema ci sia un deadlock?
- Produttore/consumatore con scambio di messaggi
- File system da cosa è costituito?
- Bit di protezione
- Set user id
- Free list, bitmap

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

- pipe (std in / out)


- pipe nome
- chiave
- funzione ftok
- system call
- interrupt volontario
- il kernel è prelazionabile?
- scheduler: breve - medio - lungo termine
- cambio coda RR (priorità)
- code separate
- come assegnare priorità (cpu burst - io bound)
- segmentazione
- struttura di un processo (eseguibile?)
- spazio indirizzamento logico
- dma
- dov'è il dma
- diffrenza tra dma breakpoint - interrupt
- cpu bound - io bound
- chi divide la memoria in segmenti
- gestione della memoria kernel linux
- processi kernel, come vengono gestiti in memoria
- segmentazione
- che sono i segmenti
- un processo kernel può essere segmentato?
- un processo kernel come viene allocato?
- Algoritmo dello zaino
- prod - cons (variabile di condizione)
- busy waiting
- In quale stato si trova un processo quando fa busy waiting e quando non lo fa

133