PROCESS MANAGEMENT:
STRUTTURE DATI
Non residente
Residente
Sintesi fin qui
Switcher
System calls
Interrupt Handlers
Processi
utente
Processo 1
I/O drivers
Daemon
Processo 2
Memoria centrale
Processo n
Periferiche
Immagine di un processo
• L’immagine di memoria di un processo è
organizzata in tre regioni:
E’ rientrante, e può
essere condiviso
fra più processi
Stack
Dati
Testo
• Ogni regione è uno spazio di indirizzamento
autonomo
Che cosa genera il compilatore C
#include ...
char buffer[1000];
int version=1;
main(int argc, char *argv[])
{ int i;
while ...
...
exit (0);
NON
INIZIALIZZATI
INIZIALIZZATI
STACK
}
int fun(int n)
int j;
{
if ...
...
}
TESTO
Formato di un eseguibile
Un eseguibile è costituito da un insieme di header e
un insieme di sezioni, contenenti codice o dati:
Main header, con magic number
Header della Sezione 1
Header della Sezione 2
Sezione 1
Sezione 2
Non residente
Residente
Sintesi fin qui
Switcher
System calls
Interrupt Handlers
I/O drivers
Stack
Stack
Stack
Dati
Dati
Dati
Testo
Testo
Testo
Processo 1
Processo 2
Processo n
Memoria centrale
Periferiche
Strutture dati per la gestione dei processi
Process Table
– si trova nel kernel, ed è residente
– contiene una entry per ogni processo, ed è dimensionata
staticamente al momento della configurazione del sistema
– per ogni processo contiene le informazioni che ne
permettono la schedulazione, e che devono essere sempre
residenti
U-Area (user area)
- si trova nel kernel, ma non è residente
- contiene quelle informazioni necessarie al kernel per la
gestione del processo, ma che non è necessario che siano
sempre residenti in memoria
Ready Queue
- Liste dei processi ready (una per ciascun livello di priorità)
Strutture dati per la gestione dei processi
• PID
0
1
• PPID
2
3
4
• UID del proprietario
…
Process Table
• Stato del processo
• Flag di residenza
• Parametri di
schedulazione (priorità,
tempo di CPU usato,
tempo di attesa)
• Dimensione del processo
• Maschere per i segnali
• ….
U-Area
Strutture dati per la gestione dei processi
• Ptr alla Process Table entry
• Registers & PC save area
• Stack del kernel per il
processo
• Info relative alla system call
corrente
0
1
2
3
4
…
Stack
Process Table
• File descriptors dei file
aperti dal processo
Dati
• Parametri per operazioni di
I/O
Testo
• Directory corrente e root
directory
Processo
• Informazioni per
l’accounting
• Puntatori alle region del
processo
U-Area
•….
Text Table
Priorità
Strutture dati per la gestione dei processi
0
1
2
1
0
2
3
4
-1
-2
…
Stack
Process Table
Ready Q
Dati
Testo
Lista dei processi che
hanno priorità 0
Processo
U-Area
Text Table
Sintesi fin qui
Kernel
Ready queue
Switcher
Process Table
System calls
Interrupt handlers
U-Area
U-Area
U-Area
Stack
Stack
Stack
Dati
Dati
Dati
Testo
Testo
Testo
Processo 1
Processo 2
Processo n
MEMORY MANAGEMENT
Paginazione
• Le versioni non “antiche” di Unix utilizzano tecniche
di paginazione
• Per eseguire un processo è sufficiente che in
memoria siano presenti almeno:
– la sua u-area
– la sua tabella delle pagine
• Le pagine di testo, dati e stack sono portate
dinamicamente in memoria dal kernel, una alla volta,
quando servono (cioè a seguito di un page fault)
• Se u-area e tabella delle pagine non sono in
memoria, ve le porta il processo swapper
Pagedaemon
• E’ un demone che viene eseguito
periodicamente per controllare il numero di
pagine libere in memoria:
• Se è troppo basso, libera qualche pagina
• Se è ok, ritorna inattivo
Swapper
E’ un processo di sistema che:
• Se le pagine libere sono sotto il minimo, rimuove uno
o più processi dalla memoria (in genere quelli inattivi
da più tempo): SWAPOUT
• Verifica periodicamente la esistenza di processi
pronti su disco e, se possibile, li carica in memoria
(solo u-area e tabella delle pagine)
(in genere quelli fuori da più tempo, a meno che non
siano troppo grossi): SWAPIN
PROCESS MANAGEMENT:
SYSTEM CALL
Processi in Unix
• In Unix, ogni processo viene creato dal kernel su
richiesta di un altro processo (detto processo padre),
mediante una apposita system call (fork)
• Esiste un processo iniziale (PID=0) che non ha
padre, e che viene creato dal kernel al momento
della inizializzazione del sistema
• Ogni processo si termina attraverso una apposita
system call (exit)
Creazione di un processo
In Unix un nuovo processo viene creato
esclusivamente per duplicazione di un processo
esistente, attraverso la system call:
pid_t fork(void);
che crea un processo “figlio” identico al padre, e
restituisce:
al figlio:
0
al padre:
PID del figlio
in caso di errore:
-1
L’unica eccezione è il processo 0, che viene creato
alla inizializzazione del sistema
Fork: esempio
p = fork();
if p < 0
{ /* la fork è fallita */ }
else if p=0 { /* operazioni del figlio */ }
else
{ /* operazioni del padre */ }
In Unix non esiste alcuna system call per “creare un
processo che esegue l’eseguibile x”
Devo farlo utilizzando più system call…
Creazione di un processo
Kernel
Ready queue
P= n
P=fork()
Switcher
Process Table
System calls
U-Area
U-Area
Stack
Stack
Dati
Dati
Testo
Processo Padre
Processo Figlio
Interrupt handlers
P=0
Che cosa fa la fork
• Alloca una entry nella Process Table per il nuovo
•
•
•
•
•
•
processo
Assegna un PID unico al nuovo processo e inizializza
i campi della Process Table entry
Crea una copia della immagine del processo padre (il
testo non viene duplicato ma si incrementa un
reference count)
Incrementa opportuni contatori dei file aperti
Inizializza i contatori di accounting nella u-area del
nuovo processo
Pone il nuovo processo nello stato di pronto
Restituisce il PID del figlio al padre, 0 al figlio o -1 in
caso di errore
Le system call exec
exec (pathname, argomenti)
• sostituisce l’immagine del chiamante con il
file eseguibile pathname, e lo manda in
esecuzione passandogli gli argomenti
p = fork();
if p < 0
else if p=0
else
{ /* la fork è fallita */ }
{ /* operazioni del figlio */ } exec (…)
{ /* operazioni del padre */ }
Creazione di un processo
Kernel
Ready queue
Switcher
Process Table
System calls
U-Area
U-Area
Stack
Stack
Dati
Dati
Testo
Processo Padre
Processo Figlio
Interrupt handlers
Exec
Kernel
Ready queue
Switcher
Process Table
System calls
U-Area
U-Area
Stack
Stack
Dati
Dati
Testo
Testo
Processo Padre
Processo Figlio
Interrupt handlers
Terminazione di un processo
In Unix un processo si termina attraverso la
system call
void _exit(int status);
che:
- termina il processo chiamante;
- rende disponibile al processo padre il valore di
status, mettendolo nella propria process table entry
- (il padre potrà ottenerlo tramite la primitiva wait)
Wait
pid_t wait (int *status)
- sospende il processo chiamante fino a che
uno dei suoi figli termina
- restituisce il PID del figlio terminato (di uno a
caso se sono più di uno) o –1 se non ci sono
figli
- assegna a status l’exit status del figlio
Exit: esempio
padre
figlio
…
…
int st; 0
exit (0)
….
….
wait ( &st )
…
0
process table entry del figlio
Exit
Kernel
Ready queue
Switcher
Process Table
System calls
U-Area
U-Area
Stack
Stack
Dati
Dati
Testo
Testo
Processo Padre
Processo Figlio
Interrupt handlers
La process table entry del
figlio non può essere
rimossa fino a quando il
valore di status in essa
contenuto non è stato
prelevato dal padre
Zombie e orfani
• un processo terminato passa nello stato di
zombie, e viene definitivamente rimosso dopo
che il padre ha ricevuto il suo stato di
terminazione con una wait
• un processo zombie occupa un insieme
minimo di risorse (process table entry)
• un processo orfano (cioè il cui padre è
terminato) viene “adottato” dal processo init,
quindi un processo ha sempre un padre
Altri stati di un processo
Running
Exit
Zombie
attesa
evento
schedulazione
quanto di tempo
esaurito
Idle
fork
Ready
Asleep
evento occorso
INIZIALIZZAZIONE
DEL SISTEMA
BOOTSTRAP
• All’accensione della macchina, l’hardware lancia il
programma di boostrap …
• … che carica in memoria il blocco di boot da disco, il
quale contiene un programma…
• …. che carica in memoria il kernel …
• … e quindi trasferisce il controllo a un entry point
(start), che crea il processo 0
Inizializzazione del sistema
bootstrap
• inizializza le strutture dati del kernel
• crea processo 1 (init): fork+exec)
Start
Processo
Ø
• crea un processo per ogni terminale attivo e i
demoni: è il padre di tutti i processi – è in loop
fork
exec
fork
exec
/etc/init
exec
/etc/getty
1
1
exec
/bin/login
LOGIN
SHELL
fork
exec
cmd
swapper
fork
exec
exec
/etc/getty
exec
/bin/login
LOGIN
SHELL
comando
è la shell di login
fork
exec
exec
/etc/getty
…….
exec
/bin/login
LOGIN
SHELL
effettua il login
fork
exec
kernel mode
user mode
demoni
inizializza il terminale
STRUTTURA DELLA SHELL
Shell: interfaccia utente
$file args
<output>
$file args&
$
esecuzione in foreground
esecuzione in background
Struttura generale della shell
$file args<>
<output>
$
write (1, PROMPT);
while ((n=read(0,buffer,80)=!0) {
riconosci nome file e args;
FIGLIO
If ( (pid=fork()) ==0) { /* I/O redirection */
if (exec(file, args)==-1) exit (1) }
PADRE
procid=wait(status);
If (status !=0) write (2, error);
write(1,PROMPT)
}
Se il comando è eseguito in background, non viene
eseguita la wait
COMUNICAZIONE FRA
PROCESSI
Interprocess communication in Unix
Unix fornisce diversi meccanismi:
• Segnali
• Pipes
• Sockets
• …
Che cos’è un segnale
• Un segnale è una notifica a un processo che è
occorso un particolare evento:
–
–
–
–
Un errore di floating point
La morte di un figlio
Una richiesta di terminazione
…
• I segnali possono essere pensati come degli
“interrupts software”
• I segnali possono essere inviati:
– da un processo a un altro processo
– da un processo a se stesso
– dal kernel a un processo
• Ogni segnale è identificato da un numero intero
associato a un nome simbolico
Segnali in POSIX
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Segnale
SIGABRT
SIGALRM
SIGCHLD
SIGCONT
SIGFPE
SIGHUP
SIGILL
SIGINT
SIGKILL
SIGPIPE
SIGQUIT
SIGSEGV
SIGSTOP
SIGTERM
SIGTSTP
SIGTTIN
17.
SIGTTOU
18.
19.
SIGUSR1
SIGUSR2
Significato (default)
Abortisce un processo (termina con dump)
Invia un segnale di "sveglia" (termina)
Lo stato di un figlio è cambiato (ignora)
Continua un processo stoppato (continua o ignora)
Floating Point Error (termina con dump)
Hangup su un terminale (termina)
Istruzione di macchina illegale (termina con dump)
Premuto il tasto DEL per interrompere il processo (termina)
Segnale per terminare un processo (non può essere ignorato) (termina)
Tentativo di scrivere su una pipe che non ha lettori (termina)
L'utente ha usato il tasto di quit del terminale (termina con dump)
Riferimento a un indirizzo di memoria non valido (termina con dump)
Per stoppare un processo (non può essere ignorato) (stoppa il processo)
Segnale per terminare un processo (termina)
L'utente ha usato il tasto "suspend" del terminale (stoppa il processo)
Un processo in background tenta di leggere dal suo terminale di controllo
(stoppa il processo)
Un processo in background tenta di scrivere sul su terminale di controllo
(stoppa il processo)
Disponibile per scopi definiti dall'applicazione
Disponibile per scopi definiti dall'applicazione
System call per gestire i segnali
• kill (PID, sig#)
invia il segnale specificato al processo o al
gruppo di processi specificato
• sigaction (sig#, action, ..)
associa a un segnale la sua funzione di
trattamento
(inizialmente: signal – non POSIX)
Come viene trattato un segnale
Quando un processo riceve un segnale, può:
1. Trattarlo mediante una specificata
funzione (“handler”)
2. Ignorarlo
3. Attivare l’azione di default associata al
segnale stesso (termina o sospendi il
processo, ignora)
Esempio
• Per terminare o sospendere un processo in
foreground, l’utente può premere i tasti CTRL-C o
CTRL-Z (rispettivamente)
• Tale carattere viene acquisito dal driver del terminale,
che notifica al processo il segnale SIGINT o
SIGTSTP (rispettivamente)
• Per default, SIGINT termina il processo e SIGTSTP
lo sospende
• NB: Tali segnali vengono inviati a tutto il gruppo di
processi
Protezione
Per motivi di protezione, deve valere
almeno una delle seguenti condizioni:
1. Il processo che riceve e il processo che
invia il segnale devono avere lo stesso
owner
2. L’owner del processo che invia il segnale è
il superuser
Strutture dati per la gestione dei segnali
0
1
0 1 1 0 0 0 0
1 2 3 4
..…
un bit per ogni segnale, che
viene alzato dalla kill
(viene ricordato solo l’ultimo
segnale di ogni tipo)
2
3
4
…
Stack
Process Table
Dati
Testo
1 2 3 4
..…
array di puntatori agli
handler definiti dall’utente
per ogni segnale
(null=default)
Processo
U-Area
Text Table