Anteprima
Vedrai una selezione di 12 pagine su 52
Appunti completi corso Sistemi Operativi Pag. 1 Appunti completi corso Sistemi Operativi Pag. 2
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 6
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 11
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 16
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 21
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 26
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 31
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 36
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 41
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 46
Anteprima di 12 pagg. su 52.
Scarica il documento per vederlo tutto.
Appunti completi corso Sistemi Operativi Pag. 51
1 su 52
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

PROCESSO PROCESSO NORMALE

THREAD PROCESSO LEGGERO

ENTRAMBI PROCESSO o TASK

Questa piccola differenza porta ad un casino con gli identificatori. Nel POSIX avevamo un

gettid())

thread ID per identificare i thread (ottenibile con la funzione e un PID che

getpid()).

identificava il processo (ottenibile con la funzione Thread appartenenti allo

stesso processo avevano lo stesso PID.

In Linux il thread ID c'è ancora sano e salvo, ma esiste un altro numero detto TGID che

numericamente è identico al PID, ma concettualmente rappresenta l'ID del THREAD

GROUP LEADER, cioè del thread di default del processo.

void *t1(void *arg) {

printf("Thread creato:\t\til TID e' %d e il TGID/PID e' %d\n", syscall(SYS_gettid), getpid());

return NULL;

}

int main(void) {

printf("Thread principale:\til TID e' %d e il TGID/PID e' %d\n", syscall(SYS_gettid), getpid());

pthread_t tID;

pthread_create(&tID, NULL, t1, NULL);

pthread_join(tID, NULL);

return 0;

}

Nel momento in cui cambia il processo in esecuzione, si ha una COMMUTAZIONE DI

CONTESTO o CONTEXT SWITCH. Il contesto è l'insieme delle informazioni che

riguardano lo stato di un processo in un determinato istante. Perché sai, quando un

processo viene fermato poi deve ripartire, e bisogna sapere in che punto era, qual era il

contenuto dei registri, il contenuto della pila ecc...

Tutto questo è nelle mani dello scheduler, che decide quale processo mandare in

esecuzione rispettando una certa POLITICA DI SCHEDULING. Essa è spesso basata su

priorità (i processi più importanti vanno eseguiti prima di quelli meno importanti) e quando

più processi hanno la stessa priorità devono essere eseguiti in maniera equa (FAIR), per

cui un processo non deve aspettare per il proprio turno troppo tempo più degli altri. È lo

scheduler stesso inoltre ad effettuare il cambio di contesto, spostando i dati che servono

dove servono.

Adesso inizia una serie di informazioni messe alla rinfusa senza alcun ordine logico.

SISTEMI MULTI-PROCESSORE

Con l'arrivo dei multi-processori si è complicato tutto e Linux ne ha tenuto conto.

L'architettura meglio supportata da Linux per il multi-processore è il SMP (Symmetric

MultiProcessing). Si suppone che ci siano più processori collegati ad una memoria

centrale condivisa, con accesso a tutte le periferiche ed un unico sistema operativo. I core

presenti su un solo processore vengono visti come processori distinti. In questa

architettura Linux alloca un solo processo per ogni processore distinto (ALLOCAZIONE

STATICA) e ognuno di essi ha il proprio PROCESSO CORRENTE. La riallocazione

avviene solo se, con un controllo periodico, si verifica che un processore è troppo

sbilanciato rispetto agli altri (LOAD BALANCING). È comunque un'operazione costosa

perché la riallocazione da un processore all'altro comporta lo svuotamento della cache. È

il modello utilizzato nei normali PC multicore, in cui i processori e le periferiche vengono

considerati tutti sullo stesso piano senza particolari specializzazioni. Noi comunque

facciamo finta che esista un solo processore e non ci complichiamo la vita.

KERNEL NON-PREEMPTABLE

Il kernel di Linux è NON-PREEMPTABLE ovvero è proibita la preemption mentre un

processo sta eseguendo codice del kernel. In pratica ha priorità massima. È comunque

possibile compilare una versione del kernel preemptable, necessaria in alcuni sistemi real-

time, dove un servizio può essere più urgente del sistema operativo e deve essere servito

in tempo reale. Di default comunque il kernel è non-preemptable e noi considereremo

questa versione.

Linux è scritto in linguaggio C e compilato con il compilatore e linker GNU GCC. È quindi

portabile sulle piattaforme hardware dove esiste quel compilatore. Il sistema operativo è

ben legato all'hardware, con alcune funzioni dipendenti dalla specifica architettura: per

questo esistono diverse implementazioni per le varie architetture supportate, che fanno

riferimento a codici assembly diversi. L'architettura che vedremo noi è la x86-64, quella

che ho io e praticamente tutti su PC e server perché in quei settori spacca e fa tutto (per

curiosità, nel settore mobile è più diffusa l'architettura ARM).

STRUTTURA DATI DELLA GESTIONE DEI PROCESSI

Ovvero la struttura che contiene informazioni necessarie per la gestione dei processi, tra

queste anche il suo CONTESTO HARDWARE, cioè il contenuto dei registri. Queste

strutture sono il DESCRITTORE DEL PROCESSO e la PILA DI SISTEMA (sPila). Ogni

processo ha un proprio descrittore e una propria pila di sistema, e sono tutte strutture

contenute nella memoria centrale. task_struct

Il descrittore del processo è una variabile struct di tipo allocata

dinamicamente nella memoria dinamica del kernel alla creazione del processo. Questa

struct contiene un casino di informazioni: il PID, il TGIP, lo stato del processo, il contesto

thread_struct

hardware (in una sottostruttura dipendente dall'HW), il puntatore alla cima

della sPila, il puntatore alla base della sPila, variabili di scheduling, informazioni su

memoria/file system/file aperti.

E indovina un po'? Ci sono due pile! Una PILA UTENTE (uPila) e una PILA DI SISTEMA

(sPila). La prossima lezione vediamo un po' a cosa servono :D

Dicevamo che noi lavoriamo su Linux x64. Parliamo meglio di questa architettura.

I registri sono a ben 64 bit, e naturalmente ci sono un Program Counter RIP e uno Stack

Pointer RSP. La pila come di consueto sale da indirizzi alti a indirizzi bassi, ma a

push pop.

differenza di MIPS nell'x64 esistono delle apposite istruzioni di e Nel salto a

funzione i parametri e l'indirizzo di ritorno sono sempre salvati sullo stack e non nei

call ret.

registri. Le istruzioni di salto e ritorno da sottoprogramma sono e

Per far sì che le cose belle che spiegheremo funzionino, è necessario che l'hardware dia

una mano attraverso registri appositi detti STRUTTURE DATI AD ACCESSO HW. Per

esempio un registro particolare del processore è chiamato PSR (Processor State

Register) ed è il REGISTRO DI STATO contenente informazioni riguardanti lo stato

attuale del processore. Inoltre il processore può funzionare in due modalità diverse:

MODO UTENTE (USER MODE o NON PRIVILEGIATO): è la modalità con cui

– funzionano i programmi utente.

MODO SUPERVISORE (SUPERVISOR MODE o KERNEL o PRIVILEGIATO):

– modalità di esecuzione del SO.

In modo U il processore può accedere ai dati e al codice solo del processo in esecuzione,

e non di altri processi o del sistema operativo. In modo S invece il processore ha accesso

a tutta la memoria. Alcune istruzioni sono eseguibili solo in modo S e sono dette

PRIVILEGIATE. La modalità con cui opera il processore è indicata in un bit del PSR.

Tutte le istruzioni di I/O sono istruzioni privilegiate, e un programma utente può utilizzarle

solo attraverso una chiamata di sistema (system call), invocando il servizio richiesto.

Nota: l'x64 reale in realtà ha anche dei livelli di privilegio intermedi, e pure il PSR è un'astrazione

perché di registri per il controllo ce ne sono un'infinità. Visto che è un'architettura complicatissima,

noi semplifichiamo un po' le cose, perché dobbiamo CAPIRE.

SYSCALL

L'istruzione non privilegiata permette di passare dal modo U al modo S per

poter eseguire un servizio del SO. Questa istruzione salva sulla pila rispettivamente il PC

e il contenuto del PSR. Nel Program Counter e nel Registro di Stato vengono inseriti i

valori <PC, PSR> contenuti in un VETTORE DI SYSCALL. Questo vettore viene

inizializzato durante il boot di sistema e contiene in coppia l'indirizzo delle syscall con i

rispettivi bit da inserire nel PSR per consentirne l'esecuzione.

SYSRET

L'istruzione privilegiata fa l'inverso: fa tornare il controllo dal sistema operativo al

processo che aveva invocato il servizio. Di conseguenza ripristina rispettivamente il PSR e

il PC che erano memorizzati sulla pila. È un'istruzione privilegiata perché viene eseguita

dal sistema operativo al termine della funzione. Questo implica il fatto importante che non

è possibile eseguire syscall annidate.

C'è un problema però: non abbiamo specificato in quale pila vengono memorizzati PC e

PSR, e l'altra volta dicevamo che ci sono due pile. Bene. Iniziamo a dire che l'architettura

64

a 64 bit potenzialmente ammette una memoria di 2 byte, ovvero 16 EB (una roba

48

gigantesca). Nella realtà la memoria virtuale ammette “solo” 2 byte ovvero 256 TB che

47

vengono suddivisi in due blocchi da 2 byte ciascuno (128 TB). Nel primo blocco gli

indirizzi vanno da 0 a 0x0000'7FFF'FFFF'FFFF e nel secondo da 0xFFFF'8000'0000'0000

a 0xFFFF'FFFF'FFFF'FFFF. Gli indirizzi intermedi sono detti NON CANONICI e non

possono essere referenziati (il loro uso genera un errore). In modo S tutti gli indirizzi

canonici sono utilizzabili, mentre in modo U solo il primo blocco è utilizzabile.

Ora possiamo chiaramente dire che quando la CPU cambia modo di funzionamento, deve

anche cambiare pila di lavoro, cioè passare dalla uPila alla sPila, un nuovo stack a cui è

assegnato uno spazio di 8 KB. Nel passaggio da modo U a modo S la commutazione di

pila deve avvenire prima del salvataggio di dati sulla stessa. Ci servono due strutture dati

nella memoria di sistema ad accesso hardware dette USP e SSP: in USP viene salvato lo

stack pointer del modo U prima di passare in modo S, mentre SSP contiene il valore da

inserire nello stack pointer nel passaggio al modo S (ovvero la base della sPila).

Quindi la SYSCALL fa queste belle cose:

Salva SP in USP

– Carica in SP il valore di SSP (adesso punta a sPila)

– Salva su sPila l'indirizzo di ritorno

– Salva su sPila il PSR (contenente il bit di modo U)

– Carica in PC e PSR i valori presenti nel Vettore di Syscall (si passa così in modo S)

A questo punto la SYSRET fa queste altre cosette:

Ripristina il PSR presente sulla sPila (passando così in modo U)

– Ripristina l'indirizzo di ritorno presente sulla sPila

– Carica USP in SP (si torna a puntare su uPila)

Parliamo ora di INTERRUPT: sono eventi rilevati via hardware che giungono dall'esterno

e sono completamente asincroni con l'esecuzione dei processi. Ad ognuno di questi

particolari eventi è associata una funzione del SO detta gestore dell'interrupt (ISR –

Interrupt Service Routine), che è in sostanza un servizio del SO. Quando il processore

rileva

Dettagli
Publisher
A.A. 2016-2017
52 pagine
1 download
SSD Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher fiorixf2 di informazioni apprese con la frequenza delle lezioni di Sistemi operativi e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Politecnico di Milano o del prof Silvano Cristina.