impostato al \acr{pid} del padre.
\item i valori dei tempi di esecuzione della struttura \var{tms} (vedi
\secref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
-\item i \textit{file lock} (vedi \secref{sec:file_locking}), che non
+\item i \textit{lock} sui file (vedi \secref{sec:file_locking}), che non
vengono ereditati dal figlio.
\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che
per il figlio vengono cancellati.
dal processo (vedi \secref{sec:sys_unix_time}) e lo stato di terminazione,
mentre la memoria in uso ed i file aperti vengono rilasciati immediatamente. I
processi che sono terminati, ma il cui stato di terminazione non è stato
-ancora ricevuto dal padre sono chiamati \textit{zombie}, essi restano presenti
-nella tabella dei processi ed in genere possono essere identificati
-dall'output di \cmd{ps} per la presenza di una \texttt{Z} nella colonna che ne
-indica lo stato (vedi \tabref{tab:proc_proc_states}). Quando il padre
-effettuerà la lettura dello stato di uscita anche questa informazione, non più
-necessaria, verrà scartata e la terminazione potrà dirsi completamente
+ancora ricevuto dal padre sono chiamati \textit{zombie}\index{zombie}, essi
+restano presenti nella tabella dei processi ed in genere possono essere
+identificati dall'output di \cmd{ps} per la presenza di una \texttt{Z} nella
+colonna che ne indica lo stato (vedi \tabref{tab:proc_proc_states}). Quando il
+padre effettuerà la lettura dello stato di uscita anche questa informazione,
+non più necessaria, verrà scartata e la terminazione potrà dirsi completamente
conclusa.
Possiamo utilizzare il nostro programma di prova per analizzare anche questa
571 pts/0 Z 0:00 [forktest <defunct>]
572 pts/0 R 0:00 ps T
\end{verbatim} %$
-\normalsize
-e come si vede, dato che non si è fatto nulla per riceverne lo stato di
-terminazione, i tre processi figli sono ancora presenti pur essendosi
-conclusi, con lo stato di zombie e l'indicazione che sono stati terminati.
-
-La possibilità di avere degli zombie deve essere tenuta sempre presente quando
-si scrive un programma che deve essere mantenuto in esecuzione a lungo e
-creare molti figli. In questo caso si deve sempre avere cura di far leggere
-l'eventuale stato di uscita di tutti i figli (in genere questo si fa
+\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo
+stato di terminazione, i tre processi figli sono ancora presenti pur essendosi
+conclusi, con lo stato di zombie\index{zombie} e l'indicazione che sono stati
+terminati.
+
+La possibilità di avere degli zombie\index{zombie} deve essere tenuta sempre
+presente quando si scrive un programma che deve essere mantenuto in esecuzione
+a lungo e creare molti figli. In questo caso si deve sempre avere cura di far
+leggere l'eventuale stato di uscita di tutti i figli (in genere questo si fa
attraverso un apposito \textit{signal handler}, che chiama la funzione
\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa
-operazione è necessaria perché anche se gli \textit{zombie} non consumano
-risorse di memoria o processore, occupano comunque una voce nella tabella dei
-processi, che a lungo andare potrebbe esaurirsi.
+operazione è necessaria perché anche se gli \textit{zombie}\index{zombie} non
+consumano risorse di memoria o processore, occupano comunque una voce nella
+tabella dei processi, che a lungo andare potrebbe esaurirsi.
Si noti che quando un processo adottato da \cmd{init} termina, esso non
-diviene uno \textit{zombie}; questo perché una delle funzioni di \cmd{init} è
-appunto quella di chiamare la funzione \func{wait} per i processi cui fa da
-padre, completandone la terminazione. Questo è quanto avviene anche quando,
-come nel caso del precedente esempio con \cmd{forktest}, il padre termina con
-dei figli in stato di zombie: alla sua terminazione infatti tutti i suoi figli
-(compresi gli zombie) verranno adottati da \cmd{init}, il quale provvederà a
-completarne la terminazione.
+diviene uno \textit{zombie}\index{zombie}; questo perché una delle funzioni di
+\cmd{init} è appunto quella di chiamare la funzione \func{wait} per i processi
+cui fa da padre, completandone la terminazione. Questo è quanto avviene anche
+quando, come nel caso del precedente esempio con \cmd{forktest}, il padre
+termina con dei figli in stato di zombie\index{zombie}: alla sua terminazione
+infatti tutti i suoi figli (compresi gli zombie\index{zombie}) verranno
+adottati da \cmd{init}, il quale provvederà a completarne la terminazione.
-Si tenga presente infine che siccome gli zombie sono processi già usciti, non
-c'è modo di eliminarli con il comando \cmd{kill}; l'unica possibilità di
-cancellarli dalla tabella dei processi è quella di terminare il processo che
-li ha generati, in modo che \cmd{init} possa adottarli e provvedere a
-concluderne la terminazione.
+Si tenga presente infine che siccome gli zombie\index{zombie} sono processi
+già usciti, non c'è modo di eliminarli con il comando \cmd{kill}; l'unica
+possibilità di cancellarli dalla tabella dei processi è quella di terminare il
+processo che li ha generati, in modo che \cmd{init} possa adottarli e
+provvedere a concluderne la terminazione.
\subsection{Le funzioni \func{wait} e \func{waitpid}}
principale attende le richieste che vengono poi soddisfatte da una serie di
processi figli. Si è già sottolineato al paragrafo precedente come in questo
caso diventi necessario gestire esplicitamente la conclusione dei figli onde
-evitare di riempire di \textit{zombie} la tabella dei processi; le funzioni
-deputate a questo compito sono sostanzialmente due, \func{wait} e
+evitare di riempire di \textit{zombie}\index{zombie} la tabella dei processi;
+le funzioni deputate a questo compito sono sostanzialmente due, \func{wait} e
\func{waitpid}. La prima, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\noindent
è presente fin dalle prime versioni di Unix; la funzione ritorna non appena un
processo figlio termina. Se un figlio è già terminato la funzione ritorna
-immediatamente.
-
-Al ritorno, lo stato di terminazione del processo viene salvato nella
-variabile puntata da \var{status} e tutte le informazioni relative al
-processo (vedi \secref{sec:proc_termination}) vengono rilasciate. Nel
-caso un processo abbia più figli il valore di ritorno permette di
-identificare qual'è quello che è uscito.
-
-Questa funzione ha il difetto di essere poco flessibile, in quanto
-ritorna all'uscita di un figlio qualunque. Nelle occasioni in cui è
-necessario attendere la conclusione di un processo specifico occorre
+immediatamente, se più di un figlio è terminato occorre chiamare la funzione
+più volte se si vuole recuperare lo stato di terminazione di tutti quanti.
+
+Al ritorno della funzione lo stato di terminazione del figlio viene salvato
+nella variabile puntata da \var{status} e tutte le risorse del kernel relative
+al processo (vedi \secref{sec:proc_termination}) vengono rilasciate. Nel caso
+un processo abbia più figli il valore di ritorno (il \acr{pid} del figlio)
+permette di identificare qual'è quello che è uscito.
+
+Questa funzione ha il difetto di essere poco flessibile, in quanto ritorna
+all'uscita di un qualunque processo figlio. Nelle occasioni in cui è
+necessario attendere la conclusione di un processo specifico occorrerebbe
predisporre un meccanismo che tenga conto dei processi già terminati, e
-provveda a ripetere la chiamata alla funzione nel caso il processo
-cercato sia ancora attivo.
+provvedere a ripetere la chiamata alla funzione nel caso il processo cercato
+sia ancora attivo.
Per questo motivo lo standard POSIX.1 ha introdotto la funzione \func{waitpid}
che effettua lo stesso servizio, ma dispone di una serie di funzionalità più
ampie, legate anche al controllo di sessione (si veda
-\ref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
+\secref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
comportamento di \func{wait} si consiglia di utilizzare sempre questa
funzione, il cui prototipo è:
\begin{functions}
Le differenze principali fra le due funzioni sono che \func{wait} si blocca
sempre fino a che un processo figlio non termina, mentre \func{waitpid} ha la
possibilità si specificare un'opzione \const{WNOHANG} che ne previene il
-blocco; inoltre \func{waitpid} può specificare quale processo attendere sulla
-base del valore fornito dall'argomento \param{pid}, secondo lo
-specchietto riportato in \tabref{tab:proc_waidpid_pid}:
+blocco; inoltre \func{waitpid} può specificare in maniera flessibile quale
+processo attendere, sulla base del valore fornito dall'argomento \param{pid},
+secondo lo specchietto riportato in \tabref{tab:proc_waidpid_pid}.
+
\begin{table}[!htb]
\centering
\footnotesize
\begin{tabular}[c]{|c|c|p{8cm}|}
\hline
- \textbf{Valore} & \textbf{Macro} &\textbf{Significato}\\
+ \textbf{Valore} & \textbf{Opzione} &\textbf{Significato}\\
\hline
\hline
$<-1$& -- & attende per un figlio il cui \textit{process group} (vedi
Il comportamento di \func{waitpid} può inoltre essere modificato passando
delle opportune opzioni tramite l'argomento \param{option}. I valori possibili
sono il già citato \const{WNOHANG}, che previene il blocco della funzione
-quando il processo figlio non è terminato, e \const{WUNTRACED}. Quest'ultimo
-viene generalmente usato per il controllo di sessione, (trattato in
-\secref{sec:sess_job_control}) in quanto permette di identificare i processi
-bloccati. La funzione infatti in tal caso ritorna, restituendone il \acr{pid},
-se c'è un processo figlio che è entrato in stato di sleep (vedi
-\tabref{tab:proc_proc_states}) di cui non si è ancora letto lo stato (con
-questa stessa opzione). Il valore dell'opzione deve essere specificato come
-maschera binaria ottenuta con l'OR delle suddette costanti con zero. In Linux
+quando il processo figlio non è terminato, e \const{WUNTRACED} che permette di
+tracciare i processi bloccati. Il valore dell'opzione deve essere specificato
+come maschera binaria ottenuta con l'OR delle suddette costanti con zero.
+
+In genere si utilizza \const{WUNTRACED} all'interno del controllo di sessione,
+(l'argomento è trattato in \secref{sec:sess_job_control}). In tal caso infatti
+la funzione ritorna, restituendone il \acr{pid}, quando c'è un processo figlio
+che è entrato in stato di sleep (vedi \tabref{tab:proc_proc_states}) e del
+quale non si è ancora letto lo stato (con questa stessa opzione). In Linux
sono previste altre opzioni non standard relative al comportamento con i
-thread, che saranno trattate in \secref{sec:thread_xxx}.
+thread, che riprenderemo in \secref{sec:thread_xxx}.
La terminazione di un processo figlio è chiaramente un evento asincrono
rispetto all'esecuzione di un programma e può avvenire in un qualunque
In genere in un programma non si vuole essere forzati ad attendere la
conclusione di un processo per proseguire, specie se tutto questo serve solo
-per leggerne lo stato di chiusura (ed evitare la presenza di \textit{zombie}),
-per questo la modalità più usata per chiamare queste funzioni è quella di
-utilizzarle all'interno di un \textit{signal handler} (vedremo un esempio di
-come gestire \const{SIGCHLD} con i segnali in \secref{sec:sig_example}). In
-questo caso infatti, dato che il segnale è generato dalla terminazione di un
-figlio, avremo la certezza che la chiamata a \func{wait} non si bloccherà.
+per leggerne lo stato di chiusura (ed evitare la presenza di
+\textit{zombie}\index{zombie}), per questo la modalità più usata per chiamare
+queste funzioni è quella di utilizzarle all'interno di un \textit{signal
+ handler} (vedremo un esempio di come gestire \const{SIGCHLD} con i segnali
+in \secref{sec:sig_example}). In questo caso infatti, dato che il segnale è
+generato dalla terminazione di un figlio, avremo la certezza che la chiamata a
+\func{wait} non si bloccherà.
\begin{table}[!htb]
\centering
\macro{WEXITSTATUS(s)} & Restituisce gli otto bit meno significativi dello
stato di uscita del processo (passato attraverso \func{\_exit}, \func{exit}
o come valore di ritorno di \func{main}). Può essere valutata solo se
- \macro{WIFEXITED} ha restituito un valore non nullo.\\
+ \val{WIFEXITED} ha restituito un valore non nullo.\\
\macro{WIFSIGNALED(s)} & Vera se il processo figlio è terminato
in maniera anomala a causa di un segnale che non è stato catturato (vedi
\secref{sec:sig_notification}).\\
\macro{WTERMSIG(s)} & restituisce il numero del segnale che ha causato
la terminazione anomala del processo. Può essere valutata solo se
- \macro{WIFSIGNALED} ha restituito un valore non nullo.\\
+ \val{WIFSIGNALED} ha restituito un valore non nullo.\\
\macro{WCOREDUMP(s)} & Vera se il processo terminato ha generato un
file si \textit{core dump}. Può essere valutata solo se
- \macro{WIFSIGNALED} ha restituito un valore non nullo.\footnote{questa
+ \val{WIFSIGNALED} ha restituito un valore non nullo.\footnote{questa
macro non è definita dallo standard POSIX.1, ma è presente come estensione
sia in Linux che in altri Unix.}\\
\macro{WIFSTOPPED(s)} & Vera se il processo che ha causato il ritorno di
\func{waitpid} è bloccato. L'uso è possibile solo avendo specificato
- l'opzione \macro{WUNTRACED}. \\
+ l'opzione \const{WUNTRACED}. \\
\macro{WSTOPSIG(s)} & restituisce il numero del segnale che ha bloccato
- il processo, Può essere valutata solo se \macro{WIFSTOPPED} ha
+ il processo, Può essere valutata solo se \val{WIFSTOPPED} ha
restituito un valore non nullo. \\
\hline
\end{tabular}
\ctyp{int} puntata da \var{status}).
Si tenga conto che nel caso di conclusione anomala il valore restituito da
-\macro{WTERMSIG} può essere confrontato con le costanti definite in
+\val{WTERMSIG} può essere confrontato con le costanti definite in
\file{signal.h} ed elencate in \tabref{tab:sig_signal_list}, e stampato usando
le apposite funzioni trattate in \secref{sec:sig_strsignal}.
\item[\errcode{ELIBBAD}] Un interprete ELF non è in un formato
riconoscibile.
\end{errlist}
- ed inoltre anche \const{EFAULT}, \const{ENOMEM}, \const{EIO},
- \const{ENAMETOOLONG}, \const{E2BIG}, \const{ELOOP}, \const{ENOTDIR},
- \const{ENFILE}, \const{EMFILE}.}
+ ed inoltre anche \errval{EFAULT}, \errval{ENOMEM}, \errval{EIO},
+ \errval{ENAMETOOLONG}, \errval{E2BIG}, \errval{ELOOP}, \errval{ENOTDIR},
+ \errval{ENFILE}, \errval{EMFILE}.}
\end{prototype}
La funzione \func{exec} esegue il file o lo script indicato da
\multicolumn{1}{|c|}{\textbf{Caratteristiche}} &
\multicolumn{6}{|c|}{\textbf{Funzioni}} \\
\hline
- &\func{execl\ }&\func{execlp}&\func{execle}
- &\func{execv\ }& \func{execvp}& \func{execve} \\
+ &\func{execl}\texttt{ }&\func{execlp}&\func{execle}
+ &\func{execv}\texttt{ }& \func{execvp}& \func{execve} \\
\hline
\hline
argomenti a lista &$\bullet$&$\bullet$&$\bullet$&&& \\
directory specificate dalla variabile di ambiente \var{PATH}. Il file che
viene posto in esecuzione è il primo che viene trovato. Se si ha un errore
relativo a permessi di accesso insufficienti (cioè l'esecuzione della
-sottostante \func{execve} ritorna un \errcode{EACCESS}), la ricerca viene
+sottostante \func{execve} ritorna un \errcode{EACCES}), la ricerca viene
proseguita nelle eventuali ulteriori directory indicate in \var{PATH}; solo se
non viene trovato nessun altro file viene finalmente restituito
-\errcode{EACCESS}.
+\errcode{EACCES}.
Le altre quattro funzioni si limitano invece a cercare di eseguire il file
indicato dal parametro \var{path}, che viene interpretato come il
corrente.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
- di fallimento: l'unico errore possibile è \const{EPERM}.}
+ di fallimento: l'unico errore possibile è \errval{EPERM}.}
\end{functions}
Il funzionamento di queste due funzioni è analogo, per cui considereremo solo
specificati da \var{rgid} e \var{egid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
- di fallimento: l'unico errore possibile è \const{EPERM}.}
+ di fallimento: l'unico errore possibile è \errval{EPERM}.}
\end{functions}
La due funzioni sono analoghe ed il loro comportamento è identico; quanto
corrente a \var{gid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
- di fallimento: l'unico errore possibile è \const{EPERM}.}
+ di fallimento: l'unico errore è \errval{EPERM}.}
\end{functions}
Come per le precedenti le due funzioni sono identiche, per cui tratteremo solo
\var{sgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
- di fallimento: l'unico errore possibile è \const{EPERM}.}
+ di fallimento: l'unico errore è \errval{EPERM}.}
\end{functions}
Le due funzioni sono identiche, quanto detto per la prima riguardo gli userid
corrente.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di
- fallimento: l'unico errore possibile è \const{EFAULT} se gli indirizzi delle
+ fallimento: l'unico errore possibile è \errval{EFAULT} se gli indirizzi delle
variabili di ritorno non sono validi.}
\end{functions}
processo corrente a \var{fsgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
- di fallimento: l'unico errore possibile è \const{EPERM}.}
+ di fallimento: l'unico errore possibile è \errval{EPERM}.}
\end{functions}
\noindent queste funzioni hanno successo solo se il processo chiamante ha i
privilegi di amministratore o, per gli altri utenti, se il valore specificato
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
fallimento, nel qual caso \var{errno} assumerà gli stessi valori di
- \func{setgroups} più \const{ENOMEM} quando non c'è memoria sufficiente per
- allocare lo spazio per informazioni dei gruppi.}
+ \func{setgroups} più \errval{ENOMEM} quando non c'è memoria sufficiente
+ per allocare lo spazio per informazioni dei gruppi.}
\end{functions}
La funzione esegue la scansione del database dei gruppi (usualmente
\textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\
\hline
\hline
- \textbf{Runnable} & \texttt{R} & Il processo è in esecuzione o è pronto ad
- essere eseguito (cioè è in attesa che gli venga assegnata la CPU). \\
- \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
- risposta dal sistema, ma può essere interrotto da un segnale. \\
- \textbf{Uninterrutible Sleep} & \texttt{D} & Il processo è in
- attesa di un risposta dal sistema (in genere per I/O), e non può essere
- interrotto in nessuna circostanza. \\
+ \textbf{Runnable}& \texttt{R} & Il processo è in esecuzione o è pronto ad
+ essere eseguito (cioè è in attesa che gli
+ venga assegnata la CPU). \\
+ \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
+ risposta dal sistema, ma può essere
+ interrotto da un segnale. \\
+ \textbf{Uninterrutible Sleep}& \texttt{D} & Il processo è in
+ attesa di un risposta dal sistema (in
+ genere per I/O), e non può essere
+ interrotto in nessuna circostanza. \\
\textbf{Stopped} & \texttt{T} & Il processo è stato fermato con un
- \const{SIGSTOP}, o è tracciato.\\
- \textbf{Zombie} & \texttt{Z} & Il processo è terminato ma il suo stato di
- terminazione non è ancora stato letto dal padre. \\
+ \const{SIGSTOP}, o è tracciato.\\
+ \textbf{Zombie}\index{zombie} & \texttt{Z} & Il processo è terminato ma il
+ suo stato di terminazione non è ancora
+ stato letto dal padre. \\
\hline
\end{tabular}
\caption{Elenco dei possibili stati di un processo in Linux, nella colonna
\item[\errcode{EINVAL}] il valore di \param{which} non è valido.
\item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha
specificato un valore di \param{inc} negativo.
- \item[\errcode{EACCESS}] un processo senza i privilegi di amministratore ha
+ \item[\errcode{EACCES}] un processo senza i privilegi di amministratore ha
cercato di modificare la priorità di un processo di un altro utente.
\end{errlist}}
\end{prototype}
\subsection{Le \textit{race condition}\index{race condition} e i
- \textit{deadlock}}
+ \textit{deadlock}\index{deadlock}}
\label{sec:proc_race_cond}
Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
problematiche di questo tipo in \capref{cha:IPC}).
Un caso particolare di \textit{race condition} sono poi i cosiddetti
-\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
-completo di un servizio, e non il fallimento di una singola operazione. Per
-definizione un \textit{deadlock} è una situazione in cui due o più processi
-non sono più in grado di proseguire perché ciascuno aspetta il risultato di
-una operazione che dovrebbe essere eseguita dall'altro.
-
-
-L'esempio tipico di una situazione che può condurre ad un \textit{deadlock} è
-quello in cui un flag di ``occupazione'' viene rilasciato da un evento
-asincrono (come un segnale o un altro processo) fra il momento in cui lo si è
-controllato (trovandolo occupato) e la successiva operazione di attesa per lo
-sblocco. In questo caso, dato che l'evento di sblocco del flag è avvenuto
-senza che ce ne accorgessimo proprio fra il controllo e la messa in attesa,
-quest'ultima diventerà perpetua (da cui il nome di \textit{deadlock}).
+\textit{deadlock}\index{deadlock}, particolarmente gravi in quanto comportano
+spesso il blocco completo di un servizio, e non il fallimento di una singola
+operazione. Per definizione un \textit{deadlock}\index{deadlock} è una
+situazione in cui due o più processi non sono più in grado di proseguire
+perché ciascuno aspetta il risultato di una operazione che dovrebbe essere
+eseguita dall'altro.
+
+
+L'esempio tipico di una situazione che può condurre ad un
+\textit{deadlock}\index{deadlock} è quello in cui un flag di ``occupazione''
+viene rilasciato da un evento asincrono (come un segnale o un altro processo)
+fra il momento in cui lo si è controllato (trovandolo occupato) e la
+successiva operazione di attesa per lo sblocco. In questo caso, dato che
+l'evento di sblocco del flag è avvenuto senza che ce ne accorgessimo proprio
+fra il controllo e la messa in attesa, quest'ultima diventerà perpetua (da cui
+il nome di \textit{deadlock}\index{deadlock}).
In tutti questi casi è di fondamentale importanza il concetto di atomicità
visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere