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.