X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=prochand.tex;h=fe46b23f824f15b06d1443ee6b47ea4bba08c2b7;hp=3a142fc9daf884e4626ab2e79eb6608cafa45942;hb=9949b501aea36905b12f069e11743b70b3e2df57;hpb=570997eb16e7228f83d94108b9cb095b7c7a0f2a diff --git a/prochand.tex b/prochand.tex index 3a142fc..fe46b23 100644 --- a/prochand.tex +++ b/prochand.tex @@ -1,6 +1,6 @@ %% 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", @@ -80,10 +80,8 @@ posto.\footnote{la cosa si fa passando la riga \cmd{init=/bin/sh} come \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 @@ -115,7 +113,7 @@ init-+-keventd |-5*[getty] |-snort `-wwwoffled -\end{Terminal} +\end{Console} %$ \caption{L'albero dei processi, così come riportato dal comando \cmd{pstree}.} @@ -400,11 +398,8 @@ Se eseguiamo il comando, che è preceduto dall'istruzione \code{export 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 @@ -418,7 +413,8 @@ Child 3 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 @@ -488,11 +484,9 @@ se buona parte dei concetti relativi ai file verranno trattati più avanti (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 @@ -515,31 +509,34 @@ Spawned 2 child, pid 1969 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 @@ -550,17 +547,17 @@ avviene per le variabili in memoria, la posizione corrente sul file è 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 @@ -782,10 +779,8 @@ stato di terminazione. 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 @@ -797,10 +792,10 @@ Child 3 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 @@ -831,11 +826,8 @@ condizione: lanciamo il comando \cmd{forktest} in \textit{background} (vedi 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 @@ -843,7 +835,8 @@ terminale (prima dello scadere dei 10 secondi) otterremo: 570 pts/0 Z 0:00 [forktest ] 571 pts/0 Z 0:00 [forktest ] 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 @@ -851,18 +844,18 @@ sono terminati (la scritta \texttt{defunct}). 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 @@ -878,9 +871,16 @@ provvede a completarne la terminazione. 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} @@ -1376,7 +1376,7 @@ Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata 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}{ @@ -1501,7 +1501,7 @@ convenzione che il primo argomento (\var{arg0} o \var{argv[0]}) viene usato 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} @@ -1649,13 +1649,13 @@ file appartiene. 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 @@ -1665,15 +1665,17 @@ nella forma: \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 @@ -3773,6 +3775,11 @@ Introdotta a partire dal kernel 2.4.21, solo su PowerPC. Introdotta a partire dal kernel 2.6.23, disponibile solo se si è abilitato il supporto nel kernel con \texttt{CONFIG\_SECCOMP}. +% 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 + + \item[\const{PR\_GET\_SECCOMP}] Ottiene come valore di ritorno della funzione lo stato corrente del \textit{secure computing mode}, al momento attuale la funzione è totalmente inutile in quanto l'unico valore ottenibile è 0, dato @@ -4067,7 +4074,7 @@ elenco, che illustra quelle attualmente disponibili:\footnote{si fa chiusura o cambiamento dei \textit{file descriptor flag} di un \textit{file descriptor} verrà per entrambi. - Se non viene impostato il processo figlio eredita una copia della  + Se non viene impostato il processo figlio eredita una copia della \itindex{file~descriptor~table} \textit{file descriptor table} del padre e vale la semantica classica della gestione dei \textit{file descriptor}, che costituisce il comportamento ordinario di un sistema unix-like e che @@ -4097,8 +4104,11 @@ elenco, che illustra quelle attualmente disponibili:\footnote{si fa \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/ \subsection{La funzione \func{ptrace}} \label{sec:process_ptrace} @@ -4106,6 +4116,11 @@ elenco, che illustra quelle attualmente disponibili:\footnote{si fa 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} @@ -4144,6 +4159,15 @@ Da fare % 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}