From: Simone Piccardi Date: Wed, 15 Aug 2001 23:06:24 +0000 (+0000) Subject: Risistemata introduzione e panoramica sulla gestione dei processi X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=e603c6e45f005839118e2142839114c00efa3449;p=gapil.git Risistemata introduzione e panoramica sulla gestione dei processi --- diff --git a/filedir.tex b/filedir.tex index db127ae..f6ad01f 100644 --- a/filedir.tex +++ b/filedir.tex @@ -699,7 +699,7 @@ Dato che il valore numerico pu standard POSIX definisce un insieme di macro per verificare il tipo di files, queste vengono usate anche da Linux che supporta pure le estensioni per link simbolici e socket definite da BSD, l'elenco completo di tutte le macro -definite in GNU/Linux è riportato in \ntab: +definite in GNU/Linux è riportato in \ntab. \begin{table}[htb] \centering \footnotesize @@ -1356,7 +1356,7 @@ Un secondo punto da tenere presente anche ad un file che non esiste; ad esempio possiamo creare un file temporaneo nella nostra directory con un link del tipo: \begin{verbatim} -$ln -s /tmp/tmp_file temporaneo +$ ln -s /tmp/tmp_file temporaneo \end{verbatim}%$ ma anche se \file{/tmp/tmp\_file} non esiste. Aprendo in scrittura \file{temporaneo} questo verrà scritto; ma se cercassimo di accederlo in sola @@ -1420,6 +1420,9 @@ la funzione \texttt{opendir} apre uno di questi stream e la funzione parlavamo in \secref{sec:file_vfs}) in una opportuna struttura \texttt{struct dirent}. +(NdA Il resto va scritto!!! É noioso e lo farò più avanti). + + \subsection{La directory di lavoro} \label{sec:file_work_dir} @@ -1467,7 +1470,7 @@ Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} fatta per compatibilità all'indietro con BSD, che non consente di specificare la dimensione del buffer; esso deve essere allocato in precedenza ed avere una dimensione superiore a \texttt{PATH\_MAX} (di solito 256 bytes, vedi -\secref{sec:xxx_limits}; il problema è che in Linux non esiste una dimensione +\secref{sec:xxx_limits}); il problema è che in Linux non esiste una dimensione superiore per un pathname, per cui non è detto che il buffer sia sufficiente a contenere il nome del file, e questa è la ragione principale per cui questa funzione è deprecata. 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