IO_1: FILE SYSTEM
La funzione principale del FileSystem consiste nel fornire un livello di astrazione, chiamato
modello di utente, omogeneo e facile da utilizzare, sopra il mondo complesso dei dispositivi
periferici di input/output.
Per ottenere questo risultato il FS deve superare una serie di difficoltà:
- la varietà e l’evoluzione delle periferiche
- i diversi tipi di utilizzo delle periferiche e dei dati
- l’esigenza di ottimizzare il funzionamento delle periferiche e della memoria centrale.
Il modello di utente si basa sulla nozione di file, ovvero una sequenza di byte.
1. DEVICE DRIVERS
In qualsiasi istante di tempo esistono molti tipi diversi di periferiche che il sistema deve
gestire; inoltre, nel tempo tali tipi evolvono continuamente richiedendo un adeguamento
continuo del sistema.
Per superare questo problema LINUX prevede la possibilità di aggiungere al SO nuovi moduli
software, detti device drivers, ogni volta che si deve gestire una periferica di tipo nuovo.
2. VIRTUAL FILE SYSTEM (VFS)
I programmi applicativi sono resi indipendenti dall’esistenza dei diversi FS grazie ad uno strato
di software detto VFS (Virtual File System), che permette a LINUX di far coesistere diversi FS,
indirizzando le richieste di servizi alle routine del FS corretto.
Quando il VFS o un FS ha bisogno di leggere un blocco su un Volume, esso lo richiede in realtà
alla Page Cache;
- se il blocco è già in Page Cache, questa restituisce l’indirizzo di memoria del blocco
- se il blocco non è presente in Page Cache, essa alloca lo spazio necessario in una pagina e
richiede al gestore a blocchi di leggere il blocco dal dispositivo nella pagina allocata.
L_1. INTRODUZIONE A LINUX
1. GESTORE DEI PROCESSI
La funzione generale svolta da un SO può essere definita come la gestione efficiente dell’HW,
orientata a rendere più semplice il suo impiego da parte dei programmi applicativi.
Il modo fondamentale per raggiungere questo scoposi basa sulla nozione di processo come
esecutore dei programmi applicativi; pertanto, la funzione principale del SO è la creazione e
gestione dei processi.
Il supporto ai programmi applicativi si basa sulla realizzazione di macchine virtuali, dette
processi; gli utilizzatori di tali macchine sono i programmi applicativi. Un processo è quindi
una macchina virtuale che esegue un programma.
Nel sistema Linux i thread sono realizzati come particolari tipologie di processi, detti processi
leggeri, che indicano un processo creato per rappresentare un thread.
I processi “leggeri” hanno risorse proprie (PC, registri di CPU, Stack Pointer, Stdin/Stdout) e
risorse condivise con gli altri processi thread dello stesso processo “normale”, ovvero la
memoria, contenente il codice, i dati e il segmento di sistema.
Linux associa ad ogni processo (leggero o normale) un diverso PID, ma lo standard Posix
richiede che tutti i thread di uno stesso processo condividano lo stesso PID: questa doppia
convenzione genera quindi un conflitto.
Un thread group è costituito dall’insieme dei processi leggeri che appartengono allo stesso
processo normale; ogni processo possiede un TGID (Thread Gruop ID) oltre al PID. Ad ogni
processo è quindi associata la coppia di identificatori <PID, TGID>.
La funzione fondamentale svolta da un sistema operativo come Linux è l’esecuzione di
diversi processi in parallelo, come se esistesse un processore per ognuno di essi. Per
ottenere questo effetto, Linux deve far eseguire al processore i programmi dei diversi processi
in alternanza (time-sharing).
La sostituzione di un processo in esecuzione con un altro è chiamata commutazione di
contesto (Context Switch). Con il termine contesto di un processo s’intende l’insieme di
informazioni relative ad ogni processo che il S.O. gestisce (parte in CPU e parte in memoria).
Ad ogni processo è associato un quanto di tempo; alla scadenza del quanto, il processo viene
sospeso (preemption) dall’esecuzione e un nuovo processo può utilizzare il processore.
Un processo può essere sospeso dall’esecuzione per due motivi:
- allo scadere del quanto o per soddisfare le esigenze di processi a priorità maggiore
- per sospensione volontaria dopo aver richiesto un servizio di sistema (operazione di I/O).
Il componente del SO che decide quale processo mandare in esecuzione, e quindi attuare la
commutazione di contesto, è detto scheduler.
Gli obiettivi della Politica di Scheduling sono due:
- processi più importanti vengano eseguiti prima dei processi meno importanti
- processi di pari importanza vengano eseguiti in maniera equa (stessa attesa).
1
L_1. INTRODUZIONE A LINUX
1.1. Sistemi multiprocessore
Il tipo di architettura multi - processore meglio supportata da Linux è l’architettura SMP
(Symmetric Multiprocessing): più processori collegati ad una memoria centrale hanno tutti
accesso ai dispositivi periferici, sono controllati da un singolo sistema operativo e vengono
considerati identici tra loro.
L’approccio di Linux al SMP consiste nell’allocare ogni task a una singola CPU in maniera
statica, e nello svolgere una riallocazione dei task tra le CPU solo quando, durante un controllo,
il carico delle CPU risulta fortemente sbilanciato (load balancing).
Il Kernel di Linux è non-preemptable, cioè è proibita la preemption (sospensione) quando un
processo esegue un codice del sistema operativo.
2. GESTIONE DELLE RISORSE HARDWARE E DELLE PERIFERICHE
Le risorse che il SO deve gestire sono le seguenti:
- processore, che deve essere assegnato all’esecuzione dei diversi processi e del SO
- memoria, che deve contenere i programmi eseguiti nei diversi processi e il SO
- periferiche, che devono essere gestite in funzione delle richieste dei diversi processi.
Per rendere trasparenti le caratteristiche delle periferiche rispetto ai programmi applicativi,
l’accesso alle periferiche avviene assimilandole a dei file speciali; in questo modo un
programma non ha necessità di conoscere i dettagli realizzativi della periferica stessa, ma
saranno i diversi gestori (driver) ad occuparsi direttamente delle caratteristiche.
Linux fornisce la possibilità di inserire nel sistema nuovi moduli software, detti
kernel_modules, senza dover ricompilare l’intero sistema; i moduli possono essere caricati
dinamicamente nel sistema durante l’esecuzione, solo quando sono necessari.
STRUTTURE DATI PER LA GESTIONE DEI PROCESSI
3.
L’informazione relativa ad ogni processo è rappresentata in strutture dati mantenute dal S.O.
Per il processo in esecuzione una parte del processo, detta contesto hardware, è
rappresentata dal contenuto dei registri della CPU; tale parte deve essere salvata nelle
strutture dati quando il processo sospende l’esecuzione, in modo da poter essere ripristinata.
Le strutture dati utilizzate per rappresentare/salvare il contesto di un processo sono:
- Descrittore del processo; una struttura dati, il cui indirizzo identifica il processo
- sPila; una pila di sistema operativo del processo, esiste una sPila per ogni processo.
2
L_1. INTRODUZIONE A LINUX
- Struttura del descrittore di processo:
Struct task_struct {
pid_t pid;
pid_t tgid;
volatile long state; // -1unrunnable, 0runnable, >0stopped
void *stack; //puntatore alla sPila del task
struct thread_struct thread; //struttura che contiene il contesto HW
//variabili per Scheduling
struct mm_struct *mm //puntatori alle strutture per gestione memoria
… } - Struttura per il contesto HW:
struct thread_struct {
…
unsigned long sp0; //puntatore alla base della sPila del processo
unsigned long sp; //puntatore alla posizione corrente della sPila
unsigned long usersp //puntatore alla pila Utente
} 3
L_2. MECCANISMI HARDWARE
I meccanismi utilizzati dal SO richiedono che l’HW acceda autonomamente a delle risorse,
registri e strutture dati in memoria, per eseguire alcune operazioni come:
- impostare dei valori che governano il funzionamento dell’HW
- leggere dei valori per conoscere lo stato dell’HW
Il registro di stato, PSR (Processor Status Register), contiene tutta l’informazione di stato che
caratterizza la situazione del processore, escluse alcune informazioni contenute in dei registri
appositi.
1. MODI DI FUNZIONAMENTO
Il processore ha la possibilità di funzionare in due modi diversi:
- modo utente: non privilegiato (quando vengono eseguiti i normali programmi)
- modo supervisore: privilegiato (quando viene eseguito il SO).
Il processore in modalità S può eseguire tutte le proprie istruzioni e può accedere a tutta la
propria memoria.
Il processore in modalità U può eseguire solo una parte delle proprie istruzioni e può accedere
solo a una parte della propria memoria.
1.1. Chiamata a sistema operativo
Esiste un’istruzione, SYSCALL, non privilegiata, che realizza un salto al SO, eseguendo un
cambio di modo di esecuzione da U a S.
La SYSCALL sostituisce oltre al PC anche il PSR della CPU con valori nuovi, salvando i valori
precedenti sulla pila; i nuovi valori vengono prelevati da una struttura ad accesso HW,
chiamata Vettore di Syscall (VdS).
La SYSCALL, simile ad un salto a funzione, opera nel modo seguente:
- il valore del PC incrementato viene salvato sulla pila (push)
- il valore del PSR viene salvato sulla pila (push)
- nel PC e PSR vengono caricati i valori presenti in una struttura dati detta vettore di Syscall
A differenza di un normale salto a funzione, la SYSCALL non indica l’indirizzo di inizio della
funzione che viene attivata, ma è il processore che lo determina leggendolo dal VdS; Linux
inizializza il VdS durante la fase di avviamento del sistema, con la coppia:
- indirizzo della funzione system_call()
- PSR opportuno per l’esecuzione di system_call(), modo privilegiato.
L’istruzione SYSRET, privilegiata, che esegue le operazioni inverse rispetto alla SYSCALL, in
modo da ritornare dal SO al processo che lo ha invocato.
1
L_2. MECCANISMI HARDWARE
1.2. Commutazione di pila
La pila utilizzata implicitamente dalla CPU nello svolgimento delle istruzioni è puntata da un
registro puntatore alla pila, lo Stack Pointer.
Per realizzare il SO è necessario fare in modo che la pila utilizzata durante il funzionamento in
modo S sia diversa da quella utilizzata durante il funzionamento in modo U; per questo motivo,
quando la CPU cambia modo di funzionamento deve anche poter sostituire il valore di SP.
Nella commutazione da modo U modo S la commutazione di pila avviene prima del salvataggio
di informazioni sulla stessa:
- l’indirizzo di ritorno a modo U deve essere salvato sulla sPila
- nel ritorno da modo S a modo U l’informazione per il ritorno verrà prelevata da sPila, cioè
prima di commutare a uPila.
Per poter commutare da modo U a modo S e attivare la sPila è necessario che l’HW possa
determinare automaticamente il valore del SP di modo S da sostituire a quello di modo U:
- SSP: contiene il valore della sPila da caricare in SP al momento del passaggio al modo S
- USP: in cui viene salvato lo SP relativo a uPila al momento del passaggio a modo S.
SYSCALL SYSRET
- Salva il valore corrente di SP in USP - Carica in PSR il valore presente in sPila
- Carica in SP il valore presente in SSP (SP - Carica in PC il valore presente in sPila
punta a sPila) - Carica in SP il valore presente in USP (SP
- Salva su sPila il PC di ritorno al punta nuovamente a USP)
programma chiamante
- Salva su sPila il valore del PSR del Il modo di funzionamento passa da S a U
programma chiamante
- Carica in PC e PSR i valori presenti nel
vettore di Syscall
Il modo di funzionamento passa da U a S 2
L_2. MECCANISMI HARDWARE
2. MECCANISMO DI INTERRUZIONE
Esistono determinati eventi rilevati dall’Hardware, a cui vengono associati particolari funzioni
dette routine di interrupt, che fanno parte del SO.
Quando il processore rileva un evento, esso interrompe il programma correntemente in
esecuzione ed esegue un salto all’esecuzione della funzione associata a tale evento; quando la
routine termina, il processore riprende l’esecuzione del programma che era stato interrotto.
Per poter riprendere l’esecuzione il processore ha salvato sulla pila, al momento del salto alla
routine di interrupt, l’indirizzo della prossima istruzione del programma interrotto, in modo
che, dopo l’esecuzione dell’interrupt, tale indirizzo sia disponibile per eseguire il ritorno.
Nel meccanismo di interrupt, il modo di arrivo è sempre S; l’istruzione privilegiata che esegue
il ritorno da interrupt è detta IRET. Di fatto, il meccanismo di interrupt è del tutto analogo ad
una invocazione di funzione o una SYSCALL.
Il processore deve sapere quale sia l’indirizzo della routine di interrupt che deve essere
eseguita quando si verifica un certo evento e il valore di PSR da utilizzare.
La tabella degli interrupt, una struttura dati ad accesso HW, contiene un certo numero di
vettori di interrupt costituiti da una coppia <PC,PSR>: esiste un meccanismo HW che è in
grado di convertire l’identificativo dell’interrupt nell’indirizzo del corrispondente vettore di
interrupt. INTERRUPT IRET
- Salva il valore corrente di SP in USP - Carica in PSR il valore di PSR presente in
- Carica in SP il valore presente in SSP (SP sPila
punta a sPila) - Carica in PC il valore dell’indirizzo di
- Salva su sPila l’indirizzo di ritorno al ritorno presente in sPila
programma interrotto - Carica in SP il valore presente in USP (SP
- Salva su sPila il valore del PSR del punta a uPila)
programma interrotto
- Carica in PC e PSR i valori presenti nel
Vettore di Interrupt
Il modo di funzionamento passa a S 3
L_3. GESTIONE DELLO STATO DEI PROCESSI
1. INTRODUZIONE
Da un punto di vista generale un processo può trovarsi in uno dei due stati fondamentali:
- Attesa: un processo in questo stato non può essere messo in esecuzione, perché deve
attendere il verificarsi di un certo evento.
- Pronto: un processo pronto è un processo che può essere messo in esecuzione se lo
scheduler lo seleziona; tra i processi in stato di pronto ne esiste uno in esecuzione, chiamato
processo corrente.
1.1. Esecuzione di un processo - contesto
Normalmente il processore esegue il codice del processo corrente in modo U. Se il processo
richiede un servizio di sistema viene attivata una funzione del SO che esegue il servizio per
conto di tale processo; un servizio è quindi svolto nel contesto di un certo processo.
Normalmente un processo è in esecuzione in modo U; si dice che un processo è in esecuzione
in modo S quando il SO è in esecuzione nel contesto di tale processo, sia per eseguire un
servizio, sia per servire un interrupt.
Il processo in stato di esecuzione abbandona tale stato solamente a causa di due eventi:
- quando un servizio di sistema richiesto dal processo deve porsi in attesa di un evento, esso
passa in stato di attesa
- quando il SO decide di sospenderne l’esecuzione a favore di un altro processo (preemption),
facendo passare il processo allo stato di pronto.
1.2. Scheduler
Il componente del SO che decide quale processo mettere in esecuzione è lo scheduler, che
svolge due tipi di funzioni:
- realizza la politica di scheduling, ovvero determina quale processo deve essere messo in
esecuzione, quando e per quanto tempo
- esegue il context switch, ovvero la sostituzione del processo corrente con un altro processo
Lo scheduler gestisce una struttura dati fondamentale (per ogni CPU), la runqueue, che a sua
volta contiene due campi:
- RB: è una lista di puntatori ai descrittori di tutti i processi pronti, escluso quello corrente
- CURR: è un puntatore al descrittore del processo corrente.
1.3. La sPila dei processi
Durante l’esecuzione di un servizio di sistema per conto di un processo (modo S), la sPila
contiene una parte del contesto HW del processo, che serve a ricostruire lo stato al momento
del ritorno al modo U.
Dato che il SO mantiene una diversa sPila per ogni processo, la gestione di questo meccanismo
diventa più complessa e richiede di salvare i valori di SSP e USP durante la sospensione tra
l’esecuzione di un processo e la successiva. Per questo il descrittore di un processo contiene:
- sp0: contiene l’indirizzo di base della sPila del processo
- sp: contiene il valore dello SP salvato al momento in cui il processo ha sospeso l’esecuzione.
1
L_3. GESTIONE DELLO STATO DEI PROCESSI
La funzione di Context Switch gestisce SSP e USP nel modo seguente:
- quando il processo è in esecuzione in modo U, la sPila è vuota, quindi in SSP viene messo il
valore di base preso da sp0 del descrittore di P
- quando la CPU passa al modo S, USP contiene il valore corretto per il ritorno al modo U
- se viene eseguita una commutazione di contesto, USP viene salvato sulla sPila di P e il valore
corrente di SP viene salvato nel campo sp del descrittore di P
- quando P riprenderà l’esecuzione, lo SP verrà ricaricato dal campo sp del descrittore,
puntando alla cima della sPila
- USP verrà ricaricato prendendolo dalla sPila
- SSP verrà ricaricato prendendolo dal campo sp0 del descrittore.
2. GESTIONE DEGLI INTERRUPT
Quando si verifica un interrupt, la situazione può appartenere ad uno dei tre sottocasi:
- l’interrupt interrompe il processo mentre funziona in modo U
- l’interrupt interrompe un servizio che è stato invocato dal processo in esecuzione
- l’interrupt interrompe una routine di interrupt relativa ad un interrupt con priorità inferiore.
In tutti questi casi, la routine di interrupt svolge la propria funzione senza disturbare il
processo in esecuzione (è trasparente) e non viene mai sostituito il processo in esecuzione
(cioè non viene mai svolta una context switch).
Se la routine di interrupt è associata al verificarsi di un evento E sul quale è in stato di attesa
u
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.