Sistemi Operativi
Sistemi Operativi
Processi in Linux
Igino Corona
[email protected]
20 Ottobre 2009
Sistemi Operativi
Contenuti della lezione
Come funzionano i programmi in Linux?
Schema base di esecuzione di un programma
Modalità utente e kernel
Chiamate a sistema (syscall)
Memoria allocata ai processi
Segmenti Text, Data e Stack
La u (user) Area
Creazione dei processi - syscall fork()
Identicatori di processo
Process IDentier - PID
Parent process Indentied - PPID
Process Group Identier - PGID
Fork e processi - esempio
Syscall Exec
Possiamo creare processi completamente diversi dal genitore?
La shell usa fork e exec
La famiglia di syscall exec
Alcuni programmi di esempio
Sistemi Operativi
Come funzionano i programmi in Linux?
Schema base di esecuzione di un programma
interpretati
processo sul
I I le eseguibili (in Linux, in formato ELF), vengono
dal sistema operativo per la creazione di un
sistema operativo.
I Un processo è di fatto un oggetto allocato in memoria avente
una struttura pressata: contiene le istruzioni del programma,
nonché diversi campi necessari (al sistema operativo) per la
sua gestione.
I In generale, quando un processo è in
esecuzione,
cioè il s.o.
sta eseguendo le istruzioni del programma, esso è allocato in
memoria principale.
Sistemi Operativi
Come funzionano i programmi in Linux?
Modalità utente e kernel
I Esistono due principali modalità di esecuzione dei processi:
utente (user mode) e kernel (kernel mode).
I I processi in modalità utente (appartenenti allo user space)
hanno gli stessi privilegi, e permessi di accesso alle risorse,
concessi agli utenti che li hanno eseguiti.
I I processi in modalità kernel (appartenenti al kernel space)
hanno invece privilegi e permessi di accesso alle risorse,
concessi al super utente root.
I Queste due modalità sono utili per proteggere l'integrità e
garantire le funzionalità del kernel di Linux: in genere sono
anche supportate a livello hardware, tramite l'instruction set
degli attuali microprocessori.
Sistemi Operativi
Come funzionano i programmi in Linux?
Chiamate a sistema (syscall)
I Esistono delle funzioni base oerte dal kernel del sistema
operativo, che fanno da interfaccia per l'accesso/gestione delle
risorse sul calcolatore, ad esempio, apertura di un le,
terminazione di un processo, creazione di una connessione
TCP, etc.
I Tali funzioni sono dette chiamate a sistema o
syscall.
I Le syscall sono implementate attraverso istruzioni contenute
nel kernel, e possono essere richiamate da un programma
utente.
I Per ogni syscall esiste una funzione di libreria C (es. libc) che
fa da wrapper.
Sistemi Operativi
Come funzionano i programmi in Linux?
Chiamate a sistema (syscall)
I Ogni volta che un programma utente esegue una syscall
(direttamente o indirettamente, tramite librerie), avviene un
cambio di contesto (context switch), poiché il processo passa
temporaneamente dalla modalità utente alla modalità kernel.
I Per limitare il tempo necessario al cambio di contesto, spesso
le chiamate al sistema per Input/Output sono inserite in un
buer.
Sistemi Operativi
Come funzionano i programmi in Linux?
Memoria allocata ai processi
Sistemi Operativi
Come funzionano i programmi in Linux?
Memoria allocata ai processi
I Ogni processo ha un suo spazio di memoria riservato, suddiviso
in
text segment, data segment e stack segment.
I
I
I
Il text segment contiene il codice eseguibile e i dati costanti.
Questa parte della memoria è leggibile ma non modicabile dal
processo e può essere condivisa da processi diversi che
eseguono lo stesso codice (in modo da risparmiare spazio in
memoria)
Il data segment contiene variabili inizializzate e non
inizializzate. Questa area può essere estesa (es. in C, tramite
malloc()).
Lo stack segment è usato dal sistema per memorizzare
identicatori automatici, variabili locali, registri e informazioni
sulle chiamate a funzione.
Sistemi Operativi
Come funzionano i programmi in Linux?
Memoria allocata ai processi
text segment, data segment e
stack segment sono forniti dalle 3 variabili C (da dichiarare
I I riferimenti alle tre zone
come
I
extern) etext, edata
e
end:
Gli indirizzi delle variabili etext, edata, end contengono
rispettivamente il primo indirizzo valido successivo ai segmenti
di testo, dei dati inizializzati e dei dati non inizializzati.
I La regione di memoria non allocata compresa tra l'indirizzo di
ne della sezione dati e la ne dello stack (n.b. che viene
riempito in senso contrario) talvolta viene chiamato anche
heap.
Sistemi Operativi
Come funzionano i programmi in Linux?
Memoria allocata ai processi
Esempio: si compili e si esegua il programma
mem_proc.c.
Associare i vari tipi di variabili alle parti della memoria del processo
in gura.
Sistemi Operativi
Come funzionano i programmi in Linux?
Memoria allocata ai processi
La
u (user) area è un area all'interno della quale il sistema
operativo immagazzina le informazioni relative ad ogni singolo
processo. Per ogni processo si tiene traccia di:
I Informazioni sulle risorse utilizzate (ad esempio les aperti)
I Directory di lavoro corrente
I Segnali giunti al processo
I System stack (le informazioni per la gestione delle chiamate a
sistema vengono memorizzate in questo stack)
I Stato del processo (dormiente, bloccato, in esecuzione)
I Proprietario del processo
La u-area è accessibile solo attraverso le system call.
Sistemi Operativi
Creazione dei processi - syscall fork()
I Quando il s.o. viene avviato, il cosiddetto
swapper (PID = 0)
è il primo processo ad essere creato (da zero) e crea il processo
init.
I Il processo
init, di PID 1, crea poi una serie di thread1
per la
gestione del s.o.
I La creazione di un nuovo processo avviene generando una
copia di un processo esistente.
I La funzione di sistema che eettua la copia di processi è la
fork()
I Il nuovo processo è dotato di un
PID (Process IDentier)
distinto.
1
In Linux un thread è un tipo speciale di processo, che condivide lo spazio
indirizzi e le risorse del genitore.
Sistemi Operativi
Creazione dei processi - syscall fork()
I La
fork()
è una funzione che normalmente restituisce due
valori distinti. Al processo glio restituisce il valore 0, al
processo padre restituisce il PID del processo glio.
I Se la funzione
fork()
fallisce restituisce il valore -1 e imposta
il valore opportuno della variabile
I Dopo la chiamata alla
fork(),
errno.
sia il padre che il glio
continuano ad essere eseguiti a partire dalla prima istruzione
successiva alla
fork().
Il fatto che venga eseguito prima il
padre o il glio dipende unicamente dall'algoritmo di
scheduling utilizzato dal kernel.
Sistemi Operativi
Creazione dei processi - syscall fork()
I Poiché i due processi sono identici (a parte il PID), per fare in
modo che il glio faccia qualcosa di diverso dal padre, occorre
che il usso di elaborazione cambi a seconda del
restituito dalla
fork().
valore
I Se un processo padre termina prima dei propri gli, il processo
init prende il posto del padre.
Sistemi Operativi
Creazione dei processi - syscall fork()
Identicatori di processo
Ciascun processo è caratterizzato da alcuni identicatori utili al
sistema operativo per la sua gestione:
I Il
PID, ovvero un numero intero che identica univocamente il
processo.
PPID, ovvero il PID del processo genitore.
Il PGID, ovvero l'identicatore del gruppo di processi al quale
I Il
I
il processo appartiene.
Sistemi Operativi
Creazione dei processi - syscall fork()
Identicatori di processo
I Il PID è un numero intero che identica univocamente un
processo
I Il sistema operativo assegna un
PID crescente ai nuovi
processi che vengono generati
I Alcuni processi del sistema operativo, poiché vengono generati
in fase di avvio sempre nello stesso ordine, hanno sempre lo
stesso
PID
I Un processo può conoscere il proprio
getpid()
PID tramite la syscall
Sistemi Operativi
Creazione dei processi - syscall fork()
Identicatori di processo
I A ciascun processo viene associato anche il
PID del processo
genitore
I La syscall
getppid()
consente di ottenere il
PID del processo
padre
I Se da un processo glio possibile risalire al processo padre, non
è possibile il percorso inverso: non esiste alcuna syscall
attraverso la quale possibile ottenere il
PID di tutti i gli di un
dato processo.
I Per tenere traccia di questa informazione, un processo padre
dovrebbe memorizzare i
volta che esso chiama la
PID che gli vengono restituiti ogni
fork().
Sistemi Operativi
Creazione dei processi - syscall fork()
Identicatori di processo
I Un processo e tutti i suoi processi gli costituiscono un gruppo
I Il processo genitore è il
process leader
I L'ID del processo genitore è anche l'identicatore del gruppo
PGID)
(
I Il concetto di gruppo molto importante per la distribuzione dei
segnali (che vedremo in seguito) tra i processi: se il processo
padre riceve un segnale di terminazione (kill), questo segnale
verrà inoltrato anche a tutti i processi gli (ovvero quelli che
fanno parte del suo gruppo)
I Tramite la syscall
getpgid(id)
un processo può conoscere
l'ID del gruppo di appartenenza
I La syscall prende in ingresso l'
id
del processo di cui si vuole
conoscere il gruppo di appartenenza (getpgid(0) specica
che vogliamo conoscere il gruppo del processo chiamante)
Sistemi Operativi
Fork e processi - esempio
fork_esempio.c illustra chiaramente qual'è
l'operazione svolta dalla fork().
NOTA: la gestione dell'errore sulla fork(): in caso di errore
fork() ritorna -1 e imposta il valore della variabile errno.
I Il programma
I
Altrimenti, al processo padre ritorna il PID del nuovo processo
creato, mentre al processo glio ritorna il valore 0.
I
I
NOTA: per utilizzare delle syscall getpid, getppid e getpgid
è necessario includere gli header <sys/types.h> e
<unistd.h>
A partire dall'output del programma, disegnare lo
schema di generazione dei processi.
Sistemi Operativi
Syscall Exec
Possiamo creare processi completamente diversi dal genitore?
In molti casi risulta utile creare nuovi processi, le cui istruzioni
(Text area), e la cui variabili (Data e Stack area) siano diverse da
quelle del processo padre.
I L'espediente consiste nel creare prima un processo glio,
tramite
fork.
I Tramite una syscall
exec si sovrascrive l'immagine (segmenti
Text, Data e Stack) del nuovo processo, e solo la u-area
rimane intatta.
I Per far ciò una
exec
necessita del nome del (o del puntatore
al) le eseguibile (e degli argomenti da passargli) da usare per
la creazione della nuova immagine del processo. In pratica,
questo corrisponde al lanciare un certo eseguibile, ed è il
ruolo principale svolto dalla shell.
I Quindi,
fork
ed
exec
congiuntamente.
sono syscall spesso utilizzate
Sistemi Operativi
Syscall Exec
La shell usa fork e exec
La shell esegue un comando esterno (es. cat) attraverso l'utilizzo
congiunto di fork e exec.
I La shell legge il comando (es. cat) e gli argomenti dal prompt
I La shell crea un glio tramite una
fork, e (di defult) resta
bloccata no alla sua terminazione (syscall
I Il glio chiama una
wait)
exec, passandole il nome del (o il puntatore
al) le eseguibile e gli argomenti estratti dal prompt (es. il le
eseguibile di nome
cat all'interno della cartella /bin/)
I Al termine del processo glio, la shell rivisualizza il prompt per
ricevere nuovi comandi
Sistemi Operativi
Syscall Exec
La famiglia di syscall exec
I Abbiamo a disposizione ben 6 syscall della famiglia
I
I
I
I
I
I
exec:
execl()
execv()
execle()
execve()
execlp()
execvp()
Queste syscall si dierenziano per la parte nale del nome ad
indicare alcune dierenze nell'acquisizione e nella tipologia
degli argomenti passati. Tutte queste chiamate restituiscono
-1 in caso di errore e impostano la variabile
successo, per denizione, non ritornano).
errno
(se hanno
Sistemi Operativi
Syscall Exec
La famiglia di syscall exec
execlp
int execlp(const char *nomele, char *arg1, ..., char *argN,
(char *) NULL);
I nomele è il nome del le eseguibile (completo di percorso sul
Esempio:
lesystem)
I
arg1,...,argN sono gli argomenti da passare al programma
I l'ultimo argomento della syscall è una stringa vuota (char
*)NULL, per indicare che tutti gli argomenti sono stati inseriti
Sistemi Operativi
Alcuni programmi di esempio
La syscall
execlp è utilizzata nei programmi clone_cat.c e
cat_ls.c.
I clone_cat.c mostra come sia possibile generare un
programma clone di cat, attraverso l'utilizzo di exec.
I
cat_ls.c mostra come sia possibile eseguire concorrentemente
un processo clone cat e uno clone di ls, attraverso l'utilizzo
congiunto di fork e exec.