%% prochand.tex
%%
-%% Copyright (C) 2000-2012 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2014
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
\begin{figure}[!htb]
\footnotesize
-\begin{Command}
-[piccardi@gont piccardi]$ pstree -n
-\end{Command}
-\begin{Terminal}
+\begin{Console}
+[piccardi@gont piccardi]$ \textbf{pstree -n}
init-+-keventd
|-kapm-idled
|-kreiserfsd
|-5*[getty]
|-snort
`-wwwoffled
-\end{Terminal}
+\end{Console}
%$
\caption{L'albero dei processi, così come riportato dal comando
\cmd{pstree}.}
\url{http://gapil.truelite.it/gapil_source.tgz}.
Decifrato il numero di figli da creare, il ciclo principale del programma
-(\texttt{\small 24--40}) esegue in successione la creazione dei processi figli
+(\texttt{\small 24-40}) esegue in successione la creazione dei processi figli
controllando il successo della chiamata a \func{fork} (\texttt{\small
- 25--29}); ciascun figlio (\texttt{\small 31--34}) si limita a stampare il
+ 25-29}); ciascun figlio (\texttt{\small 31-34}) si limita a stampare il
suo numero di successione, eventualmente attendere il numero di secondi
specificato e scrivere un messaggio prima di uscire. Il processo padre invece
-(\texttt{\small 36--38}) stampa un messaggio di creazione, eventualmente
+(\texttt{\small 36-38}) stampa un messaggio di creazione, eventualmente
attende il numero di secondi specificato, e procede nell'esecuzione del ciclo;
alla conclusione del ciclo, prima di uscire, può essere specificato un altro
periodo di attesa.
Se eseguiamo il comando, che è preceduto dall'istruzione \code{export
LD\_LIBRARY\_PATH=./} per permettere l'uso delle librerie dinamiche, senza
-specificare attese (come si può notare in (\texttt{\small 17--19}) i valori
+specificare attese (come si può notare in (\texttt{\small 17-19}) i valori
predefiniti specificano di non attendere), otterremo come risultato sul
terminale:
-\begin{Command}
-[piccardi@selidor sources]$ export LD_LIBRARY_PATH=./; ./forktest 3
-\end{Command}
-%$
-\begin{Terminal}
+\begin{Console}
+[piccardi@selidor sources]$ \textbf{export LD_LIBRARY_PATH=./; ./forktest 3}
Process 1963: forking 3 child
Spawned 1 child, pid 1964
Child 1 successfully executing
Child 3, parent 1963, exiting
Spawned 3 child, pid 1966
Go to next child
-\end{Terminal}
+\end{Console}
+%$
Esaminiamo questo risultato: una prima conclusione che si può trarre è che non
si può dire quale processo fra il padre ed il figlio venga eseguito per primo
(principalmente in sez.~\ref{sec:file_unix_interface}). Per illustrare meglio
quello che avviene si può redirigere su un file l'output del programma di
test, quello che otterremo è:
-\begin{Command}
-[piccardi@selidor sources]$ ./forktest 3 > output
-[piccardi@selidor sources]$ cat output
-\end{Command}
-\begin{Terminal}
+\begin{Console}
+[piccardi@selidor sources]$ \textbf{./forktest 3 > output}
+[piccardi@selidor sources]$ \textbf{cat output}
Process 1967: forking 3 child
Child 1 successfully executing
Child 1, parent 1967, exiting
Go to next child
Spawned 3 child, pid 1970
Go to next child
-\end{Terminal}
+\end{Console}
che come si vede è completamente diverso da quanto ottenevamo sul terminale.
Il comportamento delle varie funzioni di interfaccia con i file è analizzato
in gran dettaglio in sez.~\ref{sec:file_unix_interface} per l'interfaccia
nativa Unix ed in sez.~\ref{sec:files_std_interface} per la standardizzazione
adottata nelle librerie del linguaggio C e valida per qualunque sistema
-operativo. Qui basta accennare che si sono usate le funzioni standard della
-libreria del C che prevedono l'output bufferizzato. Il punto è che questa
-bufferizzazione (che tratteremo in dettaglio in sez.~\ref{sec:file_buffering})
-varia a seconda che si tratti di un file su disco, in cui il buffer viene
-scaricato su disco solo quando necessario, o di un terminale, in cui il buffer
-viene scaricato ad ogni carattere di a capo.
+operativo.
+
+Qui basta accennare che si sono usate le funzioni standard della libreria del
+C che prevedono l'output bufferizzato. Il punto è che questa bufferizzazione
+(che tratteremo in dettaglio in sez.~\ref{sec:file_buffering}) varia a seconda
+che si tratti di un file su disco, in cui il buffer viene scaricato su disco
+solo quando necessario, o di un terminale, in cui il buffer viene scaricato ad
+ogni carattere di a capo.
Nel primo esempio allora avevamo che, essendovi un a capo nella stringa
stampata, ad ogni chiamata a \func{printf} il buffer veniva scaricato, per cui
le singole righe comparivano a video subito dopo l'esecuzione della
\func{printf}. Ma con la redirezione su file la scrittura non avviene più alla
-fine di ogni riga e l'output resta nel buffer. Dato che ogni figlio riceve una
-copia della memoria del padre, esso riceverà anche quanto c'è nel buffer delle
-funzioni di I/O, comprese le linee scritte dal padre fino allora. Così quando
-il buffer viene scritto su disco all'uscita del figlio, troveremo nel file
-anche tutto quello che il processo padre aveva scritto prima della sua
-creazione. E alla fine del file (dato che in questo caso il padre esce per
-ultimo) troveremo anche l'output completo del padre.
+fine di ogni riga e l'output resta nel buffer.
+
+Dato che ogni figlio riceve una copia della memoria del padre, esso riceverà
+anche quanto c'è nel buffer delle funzioni di I/O, comprese le linee scritte
+dal padre fino allora. Così quando il buffer viene scritto su disco all'uscita
+del figlio, troveremo nel file anche tutto quello che il processo padre aveva
+scritto prima della sua creazione. E alla fine del file (dato che in questo
+caso il padre esce per ultimo) troveremo anche l'output completo del padre.
L'esempio ci mostra un altro aspetto fondamentale dell'interazione con i file,
valido anche per l'esempio precedente, ma meno evidente: il fatto cioè che non
condivisa fra il padre e tutti i processi figli.
Quello che succede è che quando lo \textit{standard output}\footnote{si chiama
- così il file su cui un programma scrive i suoi dati in uscita, tratteremo
- l'argomento in dettaglio in sez.~\ref{sec:file_fd}.} del padre viene
-rediretto come si è fatto nell'esempio, lo stesso avviene anche per tutti i
-figli. La funzione \func{fork} infatti ha la caratteristica di duplicare nei
-processi figli tutti i \textit{file descriptor} (vedi sez.~\ref{sec:file_fd})
-dei file aperti nel processo padre (allo stesso modo in cui lo fa la funzione
-\func{dup}, trattata in sez.~\ref{sec:file_dup}), il che comporta che padre e
-figli condividono le stesse voci della \itindex{file~table} \textit{file
- table} (tratteremo in dettaglio questi termini in
-sez.~\ref{sec:file_shared_access}) fra cui c'è anche la posizione corrente nel
-file.
+ così il file su cui di default un programma scrive i suoi dati in uscita,
+ tratteremo l'argomento in dettaglio in sez.~\ref{sec:file_fd}.} del padre
+viene rediretto come si è fatto nell'esempio, lo stesso avviene anche per
+tutti i figli. La funzione \func{fork} infatti ha la caratteristica di
+duplicare nei processi figli tutti i \textit{file descriptor} (vedi
+sez.~\ref{sec:file_fd}) dei file aperti nel processo padre (allo stesso modo
+in cui lo fa la funzione \func{dup}, trattata in sez.~\ref{sec:file_dup}), il
+che comporta che padre e figli condividono le stesse voci della
+\itindex{file~table} \textit{file table} (tratteremo in dettaglio questi
+termini in sez.~\ref{sec:file_shared_access}) fra cui c'è anche la posizione
+corrente nel file.
In questo modo se un processo scrive su un file aggiornerà la posizione
corrente sulla \itindex{file~table} \textit{file table}, e tutti gli altri
sez.~\ref{sec:file_fcntl_ioctl});
\item gli identificatori per il controllo di accesso: l'\textsl{user-ID
reale}, il \textsl{group-ID reale}, l'\textsl{user-ID effettivo}, il
- \textsl{group-ID effettivo} ed i \textit{group-ID supplementari} (vedi
+ \textsl{group-ID effettivo} ed i \textsl{group-ID supplementari} (vedi
sez.~\ref{sec:proc_access_id});
\item gli identificatori per il controllo di sessione: il
\itindex{process~group} \textit{process group-ID} e il \textit{session id}
Come verifica di questo comportamento possiamo eseguire il nostro programma
\cmd{forktest} imponendo a ciascun processo figlio due secondi di attesa prima
di uscire, il risultato è:
-\begin{Command}
-[piccardi@selidor sources]$ ./forktest -c2 3
-\end{Command}
-\begin{Terminal}[commandchars=\\\{\}]
+\begin{Console}
+[piccardi@selidor sources]$ \textbf{./forktest -c2 3}
Process 1972: forking 3 child
Spawned 1 child, pid 1973
Child 1 successfully executing
Spawned 3 child, pid 1975
Go to next child
-\textbf{[piccardi@selidor sources]$} Child 3, parent 1, exiting
+[piccardi@selidor sources]$ Child 3, parent 1, exiting
Child 2, parent 1, exiting
Child 1, parent 1, exiting
-\end{Terminal}
+\end{Console}
come si può notare in questo caso il processo padre si conclude prima dei
figli, tornando alla shell, che stampa il prompt sul terminale: circa due
secondi dopo viene stampato a video anche l'output dei tre figli che
sez.~\ref{sec:sess_job_control}), indicando al processo padre di aspettare 10
secondi prima di uscire. In questo caso, usando \cmd{ps} sullo stesso
terminale (prima dello scadere dei 10 secondi) otterremo:
-\begin{Command}
-[piccardi@selidor sources]$ ps T
-\end{Command}
-%$
-\begin{Terminal}
+\begin{Console}
+[piccardi@selidor sources]$ \textbf{ps T}
PID TTY STAT TIME COMMAND
419 pts/0 S 0:00 bash
568 pts/0 S 0:00 ./forktest -e10 3
570 pts/0 Z 0:00 [forktest <defunct>]
571 pts/0 Z 0:00 [forktest <defunct>]
572 pts/0 R 0:00 ps T
-\end{Terminal}
+\end{Console}
+%$
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 \itindex{zombie} \textit{zombie} e l'indicazione che
La possibilità di avere degli \itindex{zombie} \textit{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 sez.~\ref{sec:sig_sigchld} e
-sez.~\ref{sec:proc_wait}) di cui vedremo un esempio in
-fig.~\ref{fig:sig_sigchld_handl}.
-
-Questa operazione è necessaria perché anche se gli \itindex{zombie}
-\textit{zombie} non consumano risorse di memoria o processore, occupano
-comunque una voce nella tabella dei processi e se li si lascia accumulare a
-lungo quest'ultima potrebbe riempirsi, con l'impossibilità di lanciare nuovi
-processi.
+in esecuzione a lungo e creare molti processi figli. In questo caso si deve
+sempre avere cura di far leggere al programma l'eventuale stato di uscita di
+tutti i figli. Una modalità comune di farlo è attraverso l'utilizzo di un
+apposito \textit{signal handler} che chiami la funzione \func{wait}, (vedi
+sez.~\ref{sec:proc_wait}), ne esamineremo in dettaglio un esempio
+(fig.~\ref{fig:sig_sigchld_handl}) in sez.~\ref{sec:sig_sigchld}.
+
+La lettura degli stati di uscita è necessaria perché anche se gli
+\itindex{zombie} \textit{zombie} non consumano risorse di memoria o
+processore, occupano comunque una voce nella tabella dei processi e se li si
+lasciano accumulare a lungo quest'ultima potrebbe esaurirsi, con la
+conseguente impossibilità di lanciare nuovi processi.
Si noti tuttavia che quando un processo adottato da \cmd{init} termina, non
diviene mai uno \itindex{zombie} \textit{zombie}. Questo perché una delle
Si tenga presente infine che siccome gli \itindex{zombie} \textit{zombie} sono
processi già terminati, non c'è modo di eliminarli con il comando \cmd{kill} o
inviandogli un qualunque segnale di terminazione (l'argomento è trattato in
-sez.~\ref{sec:sig_termination}). 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 concluderne la terminazione.
+sez.~\ref{sec:sig_termination}). Qualora ci si trovi in questa situazione
+l'unica possibilità di cancellarli dalla tabella dei processi è quella di
+terminare il processo che li ha generati e che non sta facendo il suo lavoro,
+in modo che \cmd{init} possa adottarli e concluderne correttamente la
+terminazione.
+
+Si tenga anche presente che la presenza di \textit{zombie} nella tabella dei
+processi non è sempre indice di un qualche malfunzionamento, in una macchina
+con molto carico infatti può esservi una presenza temporanea dovuta al fatto
+che il processo padre ancora non ha avuto il tempo di gestirli.
\subsection{Le funzioni di attesa e ricezione degli stati di uscita}
\label{sec:proc_wait}
famiglia di funzioni) che possono essere usate per questo compito, in realtà
(come mostrato in fig.~\ref{fig:proc_exec_relat}), tutte queste funzioni sono
tutte varianti che consentono di invocare in modi diversi, semplificando il
-passaggio degli argomenti, la \textit{system call} \funcd{execve}, il cui
+passaggio degli argomenti, la funzione di sistema \funcd{execve}, il cui
prototipo è:
\begin{funcproto}{
per indicare il nome del file che contiene il programma che verrà eseguito.
\begin{figure}[!htb]
- \centering \includegraphics[width=10cm]{img/exec_rel}
+ \centering \includegraphics[width=9cm]{img/exec_rel}
\caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.}
\label{fig:proc_exec_relat}
\end{figure}
\begin{itemize*}
\item il \textit{process id} (\ids{PID}) ed il \textit{parent process id}
(\ids{PPID});
-\item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i
+\item l'\textsl{user-ID reale}, il \textsl{group-ID reale} ed i
\textsl{group-ID supplementari} (vedi sez.~\ref{sec:proc_access_id});
\item la directory radice e la \index{directory~di~lavoro} directory di lavoro
corrente (vedi sez.~\ref{sec:file_work_dir});
Se il file da eseguire è in formato \emph{a.out} e necessita di librerie
condivise, viene lanciato il \textit{linker} dinamico \cmd{/lib/ld.so} prima
del programma per caricare le librerie necessarie ed effettuare il link
-dell'eseguibile.\footnote{il formato è ormai in completo disuso, per cui è
- molto probabile che non il relativo supporto non sia disponibile.} Se il
-programma è in formato ELF per caricare le librerie dinamiche viene usato
-l'interprete indicato nel segmento \const{PT\_INTERP} previsto dal formato
-stesso, in genere questo è \sysfile{/lib/ld-linux.so.1} per programmi
-collegati con la \acr{libc5}, e \sysfile{/lib/ld-linux.so.2} per programmi
-collegati con la \acr{glibc}.
+dell'eseguibile; il formato è ormai in completo disuso, per cui è molto
+probabile che non il relativo supporto non sia disponibile. Se il programma è
+in formato ELF per caricare le librerie dinamiche viene usato l'interprete
+indicato nel segmento \const{PT\_INTERP} previsto dal formato stesso, in
+genere questo è \sysfile{/lib/ld-linux.so.1} per programmi collegati con la
+\acr{libc5}, e \sysfile{/lib/ld-linux.so.2} per programmi collegati con la
+\acr{glibc}.
Infine nel caso il programma che si vuole eseguire sia uno script e non un
binario, questo deve essere un file di testo che deve iniziare con una linea
\end{Example}
dove l'interprete indicato deve essere un eseguibile binario e non un altro
script, che verrà chiamato come se si fosse eseguito il comando
-\cmd{interpreter [argomenti] filename}.\footnote{si tenga presente che con
- Linux quanto viene scritto come \texttt{argomenti} viene passato
- all'interprete come un unico argomento con una unica stringa di lunghezza
- massima di 127 caratteri e se questa dimensione viene ecceduta la stringa
- viene troncata; altri Unix hanno dimensioni massime diverse, e diversi
- comportamenti, ad esempio FreeBSD esegue la scansione della riga e la divide
- nei vari argomenti e se è troppo lunga restituisce un errore di
- \const{ENAMETOOLONG}, una comparazione dei vari comportamenti si trova su
- \url{http://www.in-ulm.de/~mascheck/various/shebang/}.}
+\cmd{interpreter [argomenti] filename}.
+
+Si tenga presente che con Linux quanto viene scritto come \texttt{argomenti}
+viene passato all'interprete come un unico argomento con una unica stringa di
+lunghezza massima di 127 caratteri e se questa dimensione viene ecceduta la
+stringa viene troncata; altri Unix hanno dimensioni massime diverse, e diversi
+comportamenti, ad esempio FreeBSD esegue la scansione della riga e la divide
+nei vari argomenti e se è troppo lunga restituisce un errore di
+\const{ENAMETOOLONG}; una comparazione dei vari comportamenti sui diversi
+sistemi unix-like si trova su
+\url{http://www.in-ulm.de/~mascheck/various/shebang/}.
Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è
basata la gestione tradizionale dei processi in Unix: con \func{fork} si crea
\label{tab:proc_sched_policy}
\end{table}
+% TODO Aggiungere SCHED_DEADLINE, sulla nuova politica di scheduling aggiunta
+% con il kernel 3.14, vedi anche Documentation/scheduler/sched-deadline.txt e
+% http://lwn.net/Articles/575497/
+
Con le versioni più recenti del kernel sono state introdotte anche delle
varianti sulla politica di \textit{scheduling} tradizionale per alcuni carichi
di lavoro specifici, queste due nuove politiche sono specifiche di Linux e non
rimosso a partire dal kernel 2.6.25.
%TODO verificare http://lwn.net/Articles/355987/
+
\section{Funzioni di gestione avanzata}
\label{sec:proc_advanced_control}
% TODO a partire dal kernel 3.5 è stato introdotto la possibilità di usare un
% terzo argomento se il secondo è SECCOMP_MODE_FILTER, vedi
% Documentation/prctl/seccomp_filter.txt
+% vedi anche http://lwn.net/Articles/600250/
+% TODO a partire dal kernel 3.17 è stata introdotta la nuova syscall seccomp,
+% vedi http://lwn.net/Articles/600250/ e http://lwn.net/Articles/603321/
\item[\const{PR\_GET\_SECCOMP}] Ottiene come valore di ritorno della funzione
lo stato corrente del \textit{secure computing mode}, al momento attuale la
% * Documentation/prctl/seccomp_filter.txt
% * http://lwn.net/Articles/475043/
+
+% TODO documentare PR_MPX_INIT e PR_MPX_RELEASE, vedi
+% http://lwn.net/Articles/582712/
+
+% TODO documentare PR_SET_MM_MAP aggiunta con il kernel 3.18, per impostare i
+% parametri di base del layout dello spazio di indirizzi di un processo (area
+% codice e dati, stack, brack pointer ecc. vedi
+% http://git.kernel.org/linus/f606b77f1a9e362451aca8f81d8f36a3a112139e
+
+
\label{sec:prctl_operation}
\end{basedescript}
\end{basedescript}
-%TODO trattare unshare
+%TODO trattare unshare, vedi anche http://lwn.net/Articles/532748/
+
%TODO trattare kcmp aggiunta con il kernel 3.5, vedi
% https://lwn.net/Articles/478111/
Da fare
% TODO: trattare PTRACE_SEIZE, aggiunta con il kernel 3.1
+% TODO: trattare PTRACE_O_EXITKILL, aggiunta con il kernel 3.8 (vedi
+% http://lwn.net/Articles/529060/)
+% TODO: trattare PTRACE_GETSIGMASK e PTRACE_SETSIGMASK introdotte con il
+% kernel 3.11
+
\subsection{La gestione delle operazioni in virgola mobile}
% le pagine di manuale relative
% vedere anche dove metterle...
+% \subsection{La gestione dei moduli}
+% \label{sec:kernel_modules}
+
+% da fare
+
+%TODO trattare init_module e finit_module (quest'ultima introdotta con il
+%kernel 3.8)
+
+
\section{Problematiche di programmazione multitasking}
\label{sec:proc_multi_prog}