terminata da un puntatore nullo.
L'indirizzo della lista delle variabili di ambiente è passato attraverso la
-variabile globale \var{environ}, a cui si può accedere attraverso una semplice
+variabile globale \var{environ}, che viene definita automaticamente per
+cisascun processo, e a cui si può accedere attraverso una semplice
dichiarazione del tipo:
\includecodesnip{listati/env_ptr.c}
un esempio della struttura di questa lista, contenente alcune delle variabili
fig.~\ref{fig:proc_envirno_list}.
\begin{figure}[htb]
\centering
- \includegraphics[width=13cm]{img/environ_var}
+ \includegraphics[width=14cm]{img/environ_var}
\caption{Esempio di lista delle variabili di ambiente.}
\label{fig:proc_envirno_list}
\end{figure}
Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più
comuni), come riportato in tab.~\ref{tab:proc_env_var}. GNU/Linux le supporta
-tutte e ne definisce anche altre: per una lista più completa si può
-controllare \cmd{man 5 environ}.
+tutte e ne definisce anche altre, in particolare poi alcune funzioni di
+libreria prevedono la presenza di specifiche variabili di ambiente che ne
+modificano il comportamento, come quelle usate per indicare una localizzazione
+e quelle per indicare un fuso orario; una lista più completa che comprende
+queste ed ulteriori variabili si può ottenere con il comando \cmd{man 7
+ environ}.
\begin{table}[htb]
\centering
realizzato a livello delle librerie standard del C che provvedono gli
strumenti adeguati. L'uso di una \textit{variadic function} prevede quindi
tre punti:
-\begin{itemize}
+\begin{itemize*}
\item \textsl{Dichiarare} la funzione come \textit{variadic} usando un
prototipo che contenga una \textit{ellipsis}.
\item \textsl{Definire} la funzione come \textit{variadic} usando la stessa
gestione di un numero variabile di argomenti.
\item \textsl{Invocare} la funzione specificando prima gli argomenti fissi, ed
a seguire quelli addizionali.
-\end{itemize}
+\end{itemize*}
Lo standard ISO C prevede che una \index{variadic} \textit{variadic function}
abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione
sequenziale; essi verranno estratti dallo \itindex{stack} \textit{stack}
secondo l'ordine in cui sono stati scritti. Per fare questo in \file{stdarg.h}
sono definite delle apposite macro; la procedura da seguire è la seguente:
-\begin{enumerate}
+\begin{enumerate*}
\item Inizializzare un puntatore alla lista degli argomenti di tipo
\macro{va\_list} attraverso la macro \macro{va\_start}.
\item Accedere ai vari argomenti opzionali con chiamate successive alla macro
il secondo e così via.
\item Dichiarare la conclusione dell'estrazione degli argomenti invocando la
macro \macro{va\_end}.
-\end{enumerate}
+\end{enumerate*}
In generale è perfettamente legittimo richiedere meno argomenti di quelli che
potrebbero essere stati effettivamente forniti, e nella esecuzione delle
\macro{va\_arg} ci si può fermare in qualunque momento ed i restanti argomenti
immediate è quella di specificare il numero degli argomenti opzionali come uno
degli argomenti fissi. Una variazione di questo metodo è l'uso di un argomento
per specificare anche il tipo degli argomenti (come fa la stringa di formato
-per \func{printf}).
+per \func{printf}).
Una modalità diversa, che può essere applicata solo quando il tipo degli
argomenti lo rende possibile, è quella che prevede di usare un valore speciale
\subsection{Una panoramica sulle funzioni fondamentali}
\label{sec:proc_handling_intro}
-In un sistema unix-like i processi vengono sempre creati da altri processi
-tramite la funzione \func{fork}; il nuovo processo (che viene chiamato
-\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo
-processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene
-eseguito in maniera indipendente (le differenze fra padre e figlio sono
+Tradizionalmente in un sistema unix-like i processi vengono sempre creati da
+altri processi tramite la funzione \func{fork}; il nuovo processo (che viene
+chiamato \textsl{figlio}) creato dalla \func{fork} è una copia identica del
+processo processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e
+viene eseguito in maniera indipendente (le differenze fra padre e figlio sono
affrontate in dettaglio in sez.~\ref{sec:proc_fork}).
Se si vuole che il processo padre si fermi fino alla conclusione del processo
\label{sec:proc_fork}
La funzione \funcd{fork} è la funzione fondamentale della gestione dei
-processi: come si è detto l'unico modo di creare un nuovo processo è
-attraverso l'uso di questa funzione, essa quindi riveste un ruolo centrale
-tutte le volte che si devono scrivere programmi che usano il multitasking. Il
-prototipo della funzione è:
+processi: come si è detto tradizionalmente l'unico modo di creare un nuovo
+processo era attraverso l'uso di questa funzione,\footnote{in realtà oggi la
+ system call usata più comunemente da Linux per creare nuovi processi è
+ \func{clone} (vedi \ref{sec:process_clone}) , anche perché a partire dalle
+ \acr{glibc} 2.3.3 non viene più usata la system call originale, ma la stessa
+ \func{fork} viene implementata tramite \func{clone}, cosa che consente una
+ migliore interazione coi \textit{thread}.} essa quindi riveste un ruolo
+centrale tutte le volte che si devono scrivere programmi che usano il
+multitasking.\footnote{oggi questa rilevanza, con la diffusione dell'uso dei
+ \textit{thread} che tratteremo al cap.~\ref{cha:threads}, è in parte minore,
+ ma \func{fork} resta comunque la funzione principale per la creazione di
+ processi.} Il prototipo della funzione è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{unistd.h}
con il nostro esempio, le varie scritture risulteranno mescolate fra loro in
una sequenza impredicibile. Per questo le modalità con cui in genere si usano
i file dopo una \func{fork} sono sostanzialmente due:
-\begin{enumerate}
+\begin{enumerate*}
\item Il processo padre aspetta la conclusione del figlio. In questo caso non
è necessaria nessuna azione riguardo ai file, in quanto la sincronizzazione
della posizione corrente dopo eventuali operazioni di lettura e scrittura
\item L'esecuzione di padre e figlio procede indipendentemente. In questo caso
ciascuno dei due processi deve chiudere i file che non gli servono una volta
che la \func{fork} è stata eseguita, per evitare ogni forma di interferenza.
-\end{enumerate}
+\end{enumerate*}
Oltre ai file aperti i processi figli ereditano dal padre una serie di altre
proprietà; la lista dettagliata delle proprietà che padre e figlio hanno in
ed il terminale di controllo (vedi sez.~\ref{sec:sess_proc_group});
\item la directory di lavoro e la directory radice (vedi
sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot});
-\item la maschera dei permessi di creazione (vedi
+\item la maschera dei permessi di creazione dei file (vedi
sez.~\ref{sec:file_perm_management});
\item la maschera dei segnali bloccati (vedi sez.~\ref{sec:sig_sigmask}) e le
azioni installate (vedi sez.~\ref{sec:sig_gen_beha});
sez.~\ref{sec:proc_real_time} e sez.~\ref{sec:proc_sched_multiprocess});
\item le variabili di ambiente (vedi sez.~\ref{sec:proc_environ}).
\end{itemize*}
-Le differenze fra padre e figlio dopo la \func{fork} invece sono:
+Le differenze fra padre e figlio dopo la \func{fork} invece sono:\footnote{a
+ parte le ultime quattro, relative a funzionalità specifiche di Linux, le
+ altre sono esplicitamente menzionate dallo standard POSIX.1-2001.}
\begin{itemize*}
\item il valore di ritorno di \func{fork};
-\item il \acr{pid} (\textit{process id});
+\item il \acr{pid} (\textit{process id}), assegnato ad un nuovo valore univoco;
\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
impostato al \acr{pid} del padre;
-\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
- sez.~\ref{sec:sys_cpu_times}) che nel figlio sono posti a zero;
-\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}), che non
- vengono ereditati dal figlio;
-\item gli allarmi ed i segnali pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che
- per il figlio vengono cancellati.
+\item i valori dei tempi di esecuzione (vedi sez.~\ref{sec:sys_cpu_times}) e
+ delle risorse usate (vedi sez.~\ref{sec:sys_resource_use}), che nel figlio
+ sono posti a zero;
+\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}) e sulla
+ memoria (vedi sez.~\ref{sec:proc_mem_lock}), che non vengono ereditati dal
+ figlio;
+\item gli allarmi (vedi sez.~\ref{sec:sig_alarm_abort}) ed i segnali pendenti
+ (vedi sez.~\ref{sec:sig_gen_beha}), che per il figlio vengono cancellati.
+\item le operazioni di I/O asincrono in corso (vedi
+ sez.~\ref{sec:file_asyncronous_io}) che non vengono ereditate dal figlio;
+\item gli aggiustamenti fatti dal padre ai semafori con \func{semop} (vedi
+ sez.~\ref{sec:ipc_sysv_sem}).
+\item le notifiche sui cambiamenti delle directory con \textit{dnotify} (vedi
+ sez.~\ref{sec:sig_notification}), che non vengono ereditati dal figlio;
+\item le mappature di memoria marcate come \const{MADV\_DONTFORK} (vedi
+ sez.~\ref{sec:file_memory_map}) che non vengono ereditate dal figlio;
+\item l'impostazione con \func{prctl} (vedi sez.~\ref{sec:xxx_prctl}) che
+ notifica al figlio la terminazione del padre viene cancellata;
+\item il segnale di terminazione del figlio è sempre \const{SIGCHLD} anche
+ qualora nel padre fosse stato modicato (vedi sez.~\ref{sec:process_clone}).
\end{itemize*}
Una seconda funzione storica usata per la creazione di un nuovo processo è
comunque una serie di operazioni: chiude tutti i file aperti, rilascia la
memoria che stava usando, e così via; l'elenco completo delle operazioni
eseguite alla chiusura di un processo è il seguente:
-\begin{itemize}
+\begin{itemize*}
\item tutti i file descriptor sono chiusi;
\item viene memorizzato lo stato di terminazione del processo;
\item ad ogni processo figlio viene assegnato un nuovo padre (in genere
group} ciascun membro del gruppo viene bloccato, e poi gli vengono
inviati in successione i segnali \const{SIGHUP} e \const{SIGCONT}
(vedi ancora sez.~\ref{sec:sess_ctrl_term}).
-\end{itemize}
+\end{itemize*}
Oltre queste operazioni è però necessario poter disporre di un meccanismo
ulteriore che consenta di sapere come la terminazione è avvenuta: dato che in
Il comportamento di \func{waitpid} può inoltre essere modificato passando alla
funzione delle opportune opzioni tramite l'argomento \param{options}; questo
-deve essere specificato come maschera binaria dei flag riportati in
-tab.~\ref{tab:proc_waitpid_options},\footnote{oltre a queste in Linux sono
- previste del altre opzioni non standard, relative al comportamento con i
- \itindex{thread} \textit{thread}, che riprenderemo in
- sez.~\ref{sec:thread_xxx}.} che possono essere combinati fra loro con un OR
-aritmetico.
-
-L'uso dell'opzione \const{WNOHANG} consente di prevenire il blocco della
-funzione qualora nessun figlio sia uscito (o non si siano verificate le altre
-condizioni per l'uscita della funzione); in tal caso la funzione ritornerà un
-valore nullo anziché positivo.\footnote{anche in questo caso un valore
- positivo indicherà il \acr{pid} del processo di cui si è ricevuto lo stato
- ed un valore negativo un errore.}
+deve essere specificato come maschera binaria dei flag riportati nella prima
+parte in tab.~\ref{tab:proc_waitpid_options} che possono essere combinati fra
+loro con un OR aritmetico. Nella seconda parte della stessa tabella si sono
+riportati anche alcuni valori non standard specifici di Linux, che consentono
+un controllo più dettagliato per i processi creati con la system call generica
+\func{clone} (vedi sez.~\ref{sec:process_clone}) usati principalmente per la
+gestione della terminazione dei \itindex{thread} \textit{thread} (vedi
+sez.~\ref{sec:thread_xxx}).
\begin{table}[!htb]
\centering
\const{WCONTINUED}& Ritorna anche quando un processo figlio che era stato
fermato ha ripreso l'esecuzione.\footnotemark \\
\hline
+ \const{\_\_WCLONE}& Attende solo per i figli creati con \func{clone},
+ vale a dire processi che non emettono nessun segnale
+ o emettono un segnale diverso da \const{SIGCHL} alla
+ terminazione. \\
+ \const{\_\_WALL} & Attende per qualunque processo figlio. \\
+ \const{\_\_WNOTHREAD}& Non attende per i figli di altri \textit{thread}
+ dello stesso gruppo. \\
+ \hline
\end{tabular}
\caption{Costanti che identificano i bit dell'argomento \param{options}
della funzione \func{waitpid}.}
\footnotetext{disponibile solo a partire dal kernel 2.6.10.}
+L'uso dell'opzione \const{WNOHANG} consente di prevenire il blocco della
+funzione qualora nessun figlio sia uscito (o non si siano verificate le altre
+condizioni per l'uscita della funzione); in tal caso la funzione ritornerà un
+valore nullo anziché positivo.\footnote{anche in questo caso un valore
+ positivo indicherà il \acr{pid} del processo di cui si è ricevuto lo stato
+ ed un valore negativo un errore.}
+
Le altre due opzioni \const{WUNTRACED} e \const{WCONTINUED} consentono
rispettivamente di tracciare non la terminazione di un processo, ma il fatto
che esso sia stato fermato, o fatto ripartire, e sono utilizzate per la
attendono la terminazione di un processo figlio e ritornano il relativo
\acr{pid} e lo stato di terminazione nell'argomento \param{status}.
-In generale in un programma non si vuole essere forzati ad attendere la
-conclusione di un processo figlio per proseguire l'esecuzione, specie se tutto
-questo serve solo per leggerne lo stato di chiusura (ed evitare eventualmente
-la presenza di \index{zombie} \textit{zombie}). Per questo la modalità più
-comune di 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 sez.~\ref{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{waitpid} non si bloccherà.
-
-Come accennato sia \func{wait} che \func{waitpid} restituiscono lo stato di
-terminazione del processo tramite il puntatore \param{status} (se non
-interessa memorizzare lo stato si può passare un puntatore nullo). Il valore
-restituito da entrambe le funzioni dipende dall'implementazione, ma
-tradizionalmente alcuni bit (in genere 8) sono riservati per memorizzare lo
-stato di uscita, e altri per indicare il segnale che ha causato la
-terminazione (in caso di conclusione anomala), uno per indicare se è stato
-generato un \itindex{core~dump} \textit{core dump}, ecc.\footnote{le
- definizioni esatte si possono trovare in \file{<bits/waitstatus.h>} ma
- questo file non deve mai essere usato direttamente, esso viene incluso
- attraverso \file{<sys/wait.h>}.}
-
-Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
-analizzare lo stato di uscita. Esse sono definite sempre in
-\file{<sys/wait.h>} ed elencate in tab.~\ref{tab:proc_status_macro} (si tenga
-presente che queste macro prendono come parametro la variabile di tipo
-\ctyp{int} puntata da \param{status}).
-
\begin{table}[!htb]
\centering
\footnotesize
\label{tab:proc_status_macro}
\end{table}
-\footnotetext[18]{questa macro non è definita dallo standard POSIX.1-2001, ma è
+\footnotetext[20]{questa macro non è definita dallo standard POSIX.1-2001, ma è
presente come estensione sia in Linux che in altri Unix, deve essere
pertanto utilizzata con attenzione (ad esempio è il caso di usarla in un
blocco \texttt{\#ifdef WCOREDUMP ... \#endif}.}
\footnotetext{è presente solo a partire dal kernel 2.6.10.}
+In generale in un programma non si vuole essere forzati ad attendere la
+conclusione di un processo figlio per proseguire l'esecuzione, specie se tutto
+questo serve solo per leggerne lo stato di chiusura (ed evitare eventualmente
+la presenza di \index{zombie} \textit{zombie}).
+
+Per questo la modalità più comune di 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 sez.~\ref{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{waitpid} non si bloccherà.
+
+Come accennato sia \func{wait} che \func{waitpid} restituiscono lo stato di
+terminazione del processo tramite il puntatore \param{status} (se non
+interessa memorizzare lo stato si può passare un puntatore nullo). Il valore
+restituito da entrambe le funzioni dipende dall'implementazione, ma
+tradizionalmente alcuni bit (in genere 8) sono riservati per memorizzare lo
+stato di uscita, e altri per indicare il segnale che ha causato la
+terminazione (in caso di conclusione anomala), uno per indicare se è stato
+generato un \itindex{core~dump} \textit{core dump}, ecc.\footnote{le
+ definizioni esatte si possono trovare in \file{<bits/waitstatus.h>} ma
+ questo file non deve mai essere usato direttamente, esso viene incluso
+ attraverso \file{<sys/wait.h>}.}
+
+Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
+analizzare lo stato di uscita. Esse sono definite sempre in
+\file{<sys/wait.h>} ed elencate in tab.~\ref{tab:proc_status_macro}; si tenga
+presente che queste macro prevedono che gli si passi come parametro la
+variabile di tipo \ctyp{int} puntata dall'argomento \param{status} restituito
+da \func{wait} o \func{waitpid}.
+
Si tenga conto che nel caso di conclusione anomala il valore restituito da
-\val{WTERMSIG} può essere confrontato con le costanti definite in
-\file{signal.h} ed elencate in tab.~\ref{tab:sig_signal_list}, e stampato
-usando le apposite funzioni trattate in sez.~\ref{sec:sig_strsignal}.
+\val{WTERMSIG} può essere confrontato con le costanti che identificano i
+segnali definite in \file{signal.h} ed elencate in
+tab.~\ref{tab:sig_signal_list}, e stampato usando le apposite funzioni
+trattate in sez.~\ref{sec:sig_strsignal}.
A partire dal kernel 2.6.9, sempre in conformità allo standard POSIX.1-2001, è
stata introdotta una nuova funzione di attesa che consente di avere un
\end{functions}
La funzione prevede che si specifichi quali processi si intendono osservare
-usando i due argomenti \param{idtype} ed \param{id}; il primo indica se si
-vuole porsi in attesa su un singolo processo, un gruppo di processi o un
+usando i due argomenti \param{idtype} ed \param{id}; il primo indica se ci si
+vuole porre in attesa su un singolo processo, un gruppo di processi o un
processo qualsiasi, e deve essere specificato secondo uno dei valori di
tab.~\ref{tab:proc_waitid_idtype}; il secondo indica, a seconda del valore del
primo, quale processo o quale gruppo di processi selezionare.
-
\begin{table}[!htb]
\centering
\footnotesize