X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=prochand.tex;h=b337e4de05fa73b64c708a9cf62a2c6da36ad7b4;hp=3b40d63c067da2a040a08f67c9b246d53227329b;hb=e603c6e45f005839118e2142839114c00efa3449;hpb=ffde006b4b38517dd190c394b769c619d13174a5 diff --git a/prochand.tex b/prochand.tex index 3b40d63..b337e4d 100644 --- a/prochand.tex +++ b/prochand.tex @@ -16,109 +16,99 @@ funzioni a questo connesse. Partiremo con una introduzione generale ai concetti che stanno alla base della gestione dei processi in unix. Introdurremo in questa sezione l'architettura -della gestione dei processi e le sue principali caratteristiche. +della gestione dei processi e le sue principali caratteristiche, e daremo una +panoramica sull'uso delle principali funzioni per la gestione dei processi. \subsection{La gerarchia dei processi} \label{sec:proc_hierarchy} -Una delle caratteristiche essenziali di unix (che esamineremo in dettaglio più -avanti) è che ogni processo può a sua volta generare altri processi figli -(\textit{child}): questo è ad esempio quello che fa la shell quando mette in -esecuzione il programma che gli indichiamo nella linea di comando. - -Una seconda caratteristica di unix è che ogni processo viene sempre generato -in tale modo da un processo genitore (\textit{parent}) attraverso una apposita -system call. Questo vale per tutti i processi, tranne per un processo -speciale, che normalmente è \file{/sbin/init}, che invece viene lanciato dal -kernel finita la fase di avvio e che quindi non è figlio di nessuno. - -Tutto ciò significa che, come per i file su disco, i processi sono organizzati -gerarchicamente dalla relazione fra genitori e figli; alla base dell'albero in -questo caso c'è \file{init} che è progenitore di ogni altro processo. - - -\subsection{La gestione dei processi} +A differenza di quanto avviene in altri sistemi (ad esempio nel VMS la +generazione di nuovi processi è un'operazione privilegiata) una delle +caratteristiche di unix (che esamineremo in dettaglio più avanti) è che +qualunque processo può a sua volta generarne altri, detti processi figli +(\textit{child process}). Ogni processo è identificato presso il sistema da un +numero unico, il \acr{pid} (da \textit{process identifier}). + +Una seconda caratteristica è che la generazione di un processo è una +operazione separata rispetto al lancio di un programma. In genere la sequenza +è sempre quella di creare un nuovo processo, il quale si eseguirà, in un passo +successivo, il programma voluto: questo è ad esempio quello che fa la shell +quando mette in esecuzione il programma che gli indichiamo nella linea di +comando. + +Una terza caratteristica è che ogni processo viene sempre generato da un altro +che viene chiamato processo genitore (\textit{parent process}). Questo vale +per tutti i processi, con una eccezione (dato che ci deve essere un punto di +partenza), esiste sempre infatti un processo speciale, che normalmente è +\cmd{/sbin/init}, che viene lanciato dal kernel quando questo ha finito la +fase di avvio, esso essendo il primo processo lanciato ha sempre il \acr{pid} +uguale a 1 e non è figlio di nessuno. + +Questo è ovviamente un processo speciale, che in genere si occupa di far +partire tutti gli processi altri necessari al funzionamento del sistema, +inoltre \cmd{init} è essenziale per svolgere una serie di compiti +amministrativi nelle operazioni ordinarie del sistema (torneremo si alcuni di +essi in \secref{}) e non può mai essere terminato. La struttura del sistema +comunque consente di lanciare al posto di \cmd{init} qualunque altro programma +(e in casi di emergenza, ad esempio se il file di \cmd{init} si fosse +corrotto, è possibile farlo ad esempio passando la riga \cmd{init=/bin/sh} +all'avvio). + + +Dato che tutti i processi successivi sono comunque generati da \cmd{init} o da +suoi figli tutto ciò comporta che, i processi sono organizzati gerarchicamente +dalla relazione fra genitori e figli, in maniera analoga a come i file sono +organizzati in un albero di directory con alla base \file{/} (si veda +\secref{sec:file_file_struct}); in questo caso alla base dell'albero c'è il +processo \cmd{init} che è progenitore di ogni altro processo\footnote{in + realtà questo non è del tutto vero, in Linux ci sono alcuni processi che pur + comparendo come figli di init (ad esempio in \cmd{pstree}) sono generati + direttamente dal kernel, come \cmd{keventd}, \cmd{kswapd}, etc.}. + + +\subsection{Una panoramica sulle funzioni di gestione} \label{sec:proc_handling_intro} -I processi vengono creati dalla funzione \texttt{fork}; in genere questa è una -system call, ma Linux però usa un'altra nomenclatura, e la funzione fork è -basata a sua volta sulla system call \texttt{clone}, che viene usata anche per -generare i \textit{thread}. Il processo figlio creato dalla \textit{fork} è -una copia identica del processo processo padre, solo che ha un suo pid -proprio. +I processi vengono creati dalla funzione \func{fork}; in molti unix questa è +una system call, Linux però usa un'altra nomenclatura, e la funzione fork è +basata a sua volta sulla system call \func{clone}, che viene usata anche per +generare i \textit{thread}. Il processo figlio creato dalla \func{fork} è una +copia identica del processo processo padre, ma ha nuovo \acr{pid} e viene +eseguito in maniera indipendente (le differenze fra padre e figlio sono +affrontate in dettaglio in \secref{sec:proc_fork}). Se si vuole che il processo padre si fermi fino alla conclusione del processo -figlio questo deve essere specificato subito dopo la fork chiamando la -funzione \texttt{wait} o la funzione \texttt{waitpid}, che restituiscono anche -una informazione abbastanza limitata (il codice di uscita) sulle cause della -terminazione del processo. +figlio questo deve essere specificato subito dopo la \func{fork} chiamando la +funzione \func{wait} o la funzione \func{waitpid}; queste funzioni +restituiscono anche una informazione abbastanza limitata (il codice di uscita) +sulle cause della terminazione del processo. Quando un processo ha concluso il suo compito o ha incontrato un errore non -risolvibile esso può essere terminato con la funzione \texttt{exit} (si veda -quanto discusso in \secref{sec:proc_termination}). La vita del processo -però termina solo quando viene chiamata la quando la sua conclusione viene -ricevuta dal processo padre, a quel punto tutte le risorse allocate nel -sistema ad esso associate vengono rilasciate. +risolvibile esso può essere terminato con la funzione \func{exit} (si veda +quanto discusso in \secref{sec:proc_termination}). La vita del processo però +termina solo quando la notifica della sua conclusione viene ricevuta dal +processo padre, a quel punto tutte le risorse allocate nel sistema ad esso +associate vengono rilasciate. Avere due processi che eseguono esattamente lo stesso codice non è molto -utile, normalmente si genera un secondo processo per affidargli l'esecuzione di -un compito specifico (ad esempio gestire una connessione dopo che questa è +utile, normalmente si genera un secondo processo per affidargli l'esecuzione +di un compito specifico (ad esempio gestire una connessione dopo che questa è stata stabilita), o fargli eseguire (come fa la shell) un altro programma. Per -questo si usa la seconda funzione fondamentale per programmazione coi processi -che è la \texttt{exec}. +quest'ultimo caso si usa la seconda funzione fondamentale per programmazione +coi processi che è la \func{exec}. -Il programma che un processo sta eseguendo si chiama immagine del processo -(\textit{process image}), le funzioni della famiglia \func{exec} permettono -di caricare un'altro programma da disco sostituendo quest'ultimo alla process -image corrente, questo fa si che la precedente immagine venga completamente -cancellata e quando il nuovo programma esce anche il processo termina, senza -ritornare alla precedente immagine. +Il programma che un processo sta eseguendo si chiama immagine del processo (o +\textit{process image}), le funzioni della famiglia \func{exec} permettono di +caricare un'altro programma da disco sostituendo quest'ultimo all'immagine +corrente; questo fa si che l'immagine precedente venga completamente +cancellata. Questo significa che quando il nuovo programma esce anche il +processo termina, e non si può tornare alla precedente immagine. Per questo motivo la \func{fork} e la \func{exec} sono funzioni molto particolari con caratteristiche uniche rispetto a tutte le altre, infatti la prima ritorna due volte (nel processo padre e nel figlio) mentre la seconda non ritorna mai (in quanto con essa viene eseguito un altro programma). -I processi vengono creati dalla funzione \texttt{fork}; in genere questa è una -system call, ma Linux però usa un'altra nomenclatura, e la funzione fork è -basata a sua volta sulla system call \texttt{clone}, che viene usata anche per -generare i \textit{thread}. Il processo figlio creato dalla \textit{fork} è -una copia identica del processo processo padre, solo che ha un suo pid -proprio. - -Se si vuole che il processo padre si fermi fino alla conclusione del processo -figlio questo deve essere specificato subito dopo la fork chiamando la -funzione \texttt{wait} o la funzione \texttt{waitpid}, che restituiscono anche -una informazione abbastanza limitata (il codice di uscita) sulle cause della -terminazione del processo. - -Quando un processo ha concluso il suo compito o ha incontrato un errore non -risolvibile esso può essere terminato con la funzione \texttt{exit} (si veda -quanto discusso in \secref{sec:proc_termination}). La vita del processo -però termina solo quando viene chiamata la quando la sua conclusione viene -ricevuta dal processo padre, a quel punto tutte le risorse allocate nel -sistema ad esso associate vengono rilasciate. - -Avere due processi che eseguono esattamente lo stesso codice non è molto -utile, normalmente si genera un secondo processo per affidargli l'esecuzione di -un compito specifico (ad esempio gestire una connessione dopo che questa è -stata stabilita), o fargli eseguire (come fa la shell) un altro programma. Per -questo si usa la seconda funzione fondamentale per programmazione coi processi -che è la \texttt{exec}. - -Il programma che un processo sta eseguendo si chiama immagine del processo -(\textit{process image}), le funzioni della famiglia \func{exec} permettono -di caricare un'altro programma da disco sostituendo quest'ultimo alla process -image corrente, questo fa si che la precedente immagine venga completamente -cancellata e quando il nuovo programma esce anche il processo termina, senza -ritornare alla precedente immagine. - -Per questo motivo la \func{fork} e la \func{exec} sono funzioni molto -particolari con caratteristiche uniche rispetto a tutte le altre, infatti la -prima ritorna due volte (nel processo padre e nel figlio) mentre la seconda -non ritorna mai (in quanto con essa viene eseguito un altro programma). - - \section{Il controllo dei processi} \label{sec:proc_control} @@ -130,13 +120,13 @@ trattare in dettaglio le singole funzioni, \subsection{Gli identificatori dei processi} \label{sec:proc_id} -Ogni processo viene identificato dal sistema da un numero identificativo -unico, il \textit{process id} o \acr{pid}. Questo viene assegnato in forma -progressiva ogni volta che un nuovo processo viene creato, fino ad un limite -massimo (in genere essendo detto numero memorizzato in un intero a 16 bit si -arriva a 32767) oltre il quale si riparte dal numero più basso disponibile -(FIXME: verificare, non sono sicuro). Per questo motivo processo il processo -di avvio (init) ha sempre il pid uguale a uno. +Come accennato ogni processo viene identificato dal sistema da un numero +identificativo unico, il \textit{process id} o \acr{pid}. Questo viene +assegnato in forma progressiva ogni volta che un nuovo processo viene creato, +fino ad un limite massimo (in genere essendo detto numero memorizzato in un +intero a 16 bit si arriva a 32767) oltre il quale si riparte dal numero più +basso disponibile (FIXME: verificare, non sono sicuro). Per questo motivo +processo il processo di avvio (init) ha sempre il pid uguale a uno. Ogni processo è identificato univocamente dal sistema per il suo pid; quest'ultimo è un tipo di dato standard, il \texttt{pid\_t} che in genere è un