\begin{figure}[htb]
\centering
- \includegraphics[width=11cm]{img/task_struct}
+ \includegraphics[width=12cm]{img/task_struct}
\caption{Schema semplificato dell'architettura delle strutture usate dal
kernel nella gestione dei processi.}
\label{fig:proc_task_struct}
\const{HZ},\footnote{fino al kernel 2.4 il valore usuale di questa costante
era 100, per tutte le architetture eccetto l'alpha, per la quale era 1000,
nel 2.6 è stato portato a 1000 su tutte le architetture; occorre fare
- attenzione a non confondere questo valore con quello dei clock tick (vedi
+ attenzione a non confondere questo valore con quello dei
+ \itindex{clock~tick} \textit{clock tick} (vedi
sez.~\ref{sec:sys_unix_time}).} definita in \file{asm/param.h}, ed il cui
valore è espresso in Hertz.\footnote{a partire dal kernel 2.6.21 è stato
introdotto (a cura di Ingo Molnar) un meccanismo completamente diverso,
Quando un processo ha concluso il suo compito o ha incontrato un errore non
risolvibile esso può essere terminato con la funzione \func{exit} (si veda
quanto discusso in sez.~\ref{sec:proc_conclusion}). 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.
+termina completamente 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
non ritorna mai (in quanto con essa viene eseguito un altro programma).
-
\section{Le funzioni di base}% della gestione dei processi}
\label{sec:proc_handling}
basso disponibile a partire da un minimo di 300,\footnote{questi valori, fino
al kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in
\file{threads.h} e direttamente in \file{fork.c}, con il kernel 2.5.x e la
- nuova interfaccia per i thread creata da Ingo Molnar anche il meccanismo di
- allocazione dei \acr{pid} è stato modificato.} che serve a riservare i
-\acr{pid} più bassi ai processi eseguiti direttamente dal kernel. Per questo
-motivo, come visto in sez.~\ref{sec:proc_hierarchy}, il processo di avvio
-(\cmd{init}) ha sempre il \acr{pid} uguale a uno.
+ nuova interfaccia per i \itindex{thread} \textit{thread} creata da Ingo
+ Molnar anche il meccanismo di allocazione dei \acr{pid} è stato modificato;
+ il valore massimo è impostabile attraverso il file
+ \procfile{/proc/sys/kernel/pid\_max} e di default vale 32768.} che serve a
+riservare i \acr{pid} più bassi ai processi eseguiti direttamente dal kernel.
+Per questo motivo, come visto in sez.~\ref{sec:proc_hierarchy}, il processo di
+avvio (\cmd{init}) ha sempre il \acr{pid} uguale a uno.
Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
il processo figlio continuano ad essere eseguiti normalmente a partire
dall'istruzione successiva alla \func{fork}; il processo figlio è però una
copia del padre, e riceve una copia dei \index{segmento!testo} segmenti di
-testo, \itindex{stack} stack e \index{segmento!dati} dati (vedi
+testo, \itindex{stack} \textit{stack} e \index{segmento!dati} dati (vedi
sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
padre. Si tenga presente però che la memoria è copiata, non condivisa,
pertanto padre e figlio vedono variabili diverse.
senza specificare attese (come si può notare in (\texttt{\small 17--19}) i
valori predefiniti specificano di non attendere), otterremo come output sul
terminale:
-
-\footnotesize
-\begin{verbatim}
+\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm]
[piccardi@selidor sources]$ export LD_LIBRARY_PATH=./; ./forktest 3
Process 1963: forking 3 child
Spawned 1 child, pid 1964
Child 3, parent 1963, exiting
Spawned 3 child, pid 1966
Go to next child
-\end{verbatim} %$
-\normalsize
+\end{Verbatim}
+%$
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\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo
- \itindex{scheduler} \textit{scheduler} di Ingo Molnar che esegue sempre per
- primo il figlio; per mantenere la portabilità è opportuno non fare comunque
- affidamento su questo comportamento.} dopo la chiamata a \func{fork};
-dall'esempio si può notare infatti come nei primi due cicli sia stato eseguito
-per primo il padre (con la stampa del \acr{pid} del nuovo processo) per poi
-passare all'esecuzione del figlio (completata con i due avvisi di esecuzione
-ed uscita), e tornare all'esecuzione del padre (con la stampa del passaggio al
-ciclo successivo), mentre la terza volta è stato prima eseguito il figlio
-(fino alla conclusione) e poi il padre.
+si può dire quale processo fra il padre ed il figlio venga eseguito per primo
+dopo la chiamata a \func{fork}; dall'esempio si può notare infatti come nei
+primi due cicli sia stato eseguito per primo il padre (con la stampa del
+\acr{pid} del nuovo processo) per poi passare all'esecuzione del figlio
+(completata con i due avvisi di esecuzione ed uscita), e tornare
+all'esecuzione del padre (con la stampa del passaggio al ciclo successivo),
+mentre la terza volta è stato prima eseguito il figlio (fino alla conclusione)
+e poi il padre.
In generale l'ordine di esecuzione dipenderà, oltre che dall'algoritmo di
\itindex{scheduler} scheduling usato dal kernel, dalla particolare situazione
rischio di incorrere nelle cosiddette \itindex{race~condition} \textit{race
condition} (vedi sez.~\ref{sec:proc_race_cond}).
+In realtà a partire dal kernel 2.5.2-pre10 il nuovo \itindex{scheduler}
+\textit{scheduler} di Ingo Molnar esegue sempre per primo il
+figlio;\footnote{i risultati precedenti sono stati ottenuti usando un kernel
+ della serie 2.4.} questa è una ottimizzazione che serve a evitare che il
+padre, effettuando per primo una operazione di scrittura in memoria, attivi il
+meccanismo del \itindex{copy~on~write} \textit{copy on write}. Questa
+operazione infatti potrebbe risultare del tutto inutile qualora il figlio
+fosse stato creato solo per eseguire una \func{exec}, in tal caso infatti si
+invocherebbe un altro programma scartando completamente lo spazio degli
+indirizzi, rendendo superflua la copia della memoria modificata dal padre.
+
+Eseguendo sempre per primo il figlio la \func{exec} verrebbe effettuata subito
+avendo così la certezza che il \itindex{copy~on~write} \textit{copy on write}
+viene utilizzato solo quando necessario. Quanto detto in precedenza vale
+allora soltanto per i kernel fino al 2.4; per mantenere la portabilità è però
+opportuno non fare affidamento su questo comportamento, che non si riscontra
+in altri Unix e nelle versioni del kernel precendenti a quella indicata.
+
Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
processi completamente separati, le modifiche delle variabili nei processi
figli (come l'incremento di \var{i} in \texttt{\small 31}) sono visibili solo
quello dell'interazione dei vari processi con i file; per illustrarlo meglio
proviamo a redirigere su un file l'output del nostro programma di test, quello
che otterremo è:
-
-\footnotesize
-\begin{verbatim}
+\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm]
[piccardi@selidor sources]$ ./forktest 3 > output
[piccardi@selidor sources]$ cat output
Process 1967: forking 3 child
Go to next child
Spawned 3 child, pid 1970
Go to next child
-\end{verbatim}
-\normalsize
+\end{Verbatim}
che come si vede è completamente diverso da quanto ottenevamo sul terminale.
Il comportamento delle varie funzioni di interfaccia con i file è analizzato
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
+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,
le variabili, la posizione corrente sul file è condivisa fra il padre e tutti
i processi figli.
-Quello che succede è che quando lo standard output del padre viene rediretto,
-lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha
-la caratteristica di duplicare nei figli tutti i file descriptor aperti nel
-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} (per la spiegazione
-di questi termini si veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la
-posizione corrente nel file.
+Quello che succede è che quando lo standard output 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 file descriptor 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} (per la spiegazione di questi termini
+si veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la posizione corrente
+nel file.
In questo modo se un processo scrive sul file aggiornerà la posizione corrente
sulla \itindex{file~table} \textit{file table}, e tutti gli altri processi,
Questo tipo di comportamento è essenziale in tutti quei casi in cui il padre
crea un figlio e attende la sua conclusione per proseguire, ed entrambi
-scrivono sullo stesso file (un caso tipico è la shell quando lancia un
-programma, il cui output va sullo standard output).
-
-In questo modo, anche se l'output viene rediretto, il padre potrà sempre
-continuare a scrivere in coda a quanto scritto dal figlio in maniera
-automatica; se così non fosse ottenere questo comportamento sarebbe
-estremamente complesso necessitando di una qualche forma di comunicazione fra
-i due processi per far riprendere al padre la scrittura al punto giusto.
+scrivono sullo stesso file; un caso tipico è la shell quando lancia un
+programma, il cui output va sullo standard output. In questo modo, anche se
+l'output viene rediretto, il padre potrà sempre continuare a scrivere in coda
+a quanto scritto dal figlio in maniera automatica; se così non fosse ottenere
+questo comportamento sarebbe estremamente complesso necessitando di una
+qualche forma di comunicazione fra i due processi per far riprendere al padre
+la scrittura al punto giusto.
In generale comunque non è buona norma far scrivere più processi sullo stesso
file senza una qualche forma di sincronizzazione in quanto, come visto anche
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
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
terminato (si potrebbe avere cioè quello che si chiama un processo
\textsl{orfano}).
+% TODO verificare il reparenting
+
Questa complicazione viene superata facendo in modo che il processo orfano
venga \textsl{adottato} da \cmd{init}. Come già accennato quando un processo
termina, il kernel controlla se è il padre di altri processi in esecuzione: in
cui riportare il suo 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 è:
-
-\footnotesize
-\begin{verbatim}
+\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm]
[piccardi@selidor sources]$ ./forktest -c2 3
Process 1972: forking 3 child
Spawned 1 child, pid 1973
[piccardi@selidor sources]$ Child 3, parent 1, exiting
Child 2, parent 1, exiting
Child 1, parent 1, exiting
-\end{verbatim}
-\normalsize
+\end{Verbatim}
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:
-
-\footnotesize
-\begin{verbatim}
+\begin{Verbatim}[fontsize=\footnotesize,xleftmargin=1cm,xrightmargin=1.5cm]
[piccardi@selidor sources]$ ps T
PID TTY STAT TIME COMMAND
419 pts/0 S 0:00 bash
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{verbatim} %$
-\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo
+\end{Verbatim}
+%$
+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 \index{zombie} \textit{zombie} e l'indicazione che
sono stati terminati.
\textbf{Valore} & \textbf{Costante} &\textbf{Significato}\\
\hline
\hline
- $<-1$& -- & attende per un figlio il cui
+ $<-1$& -- & Attende per un figlio il cui
\itindex{process~group} \textit{process group}
(vedi sez.~\ref{sec:sess_proc_group}) è uguale
al valore assoluto di \param{pid}. \\
- $-1$&\const{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
+ $-1$&\const{WAIT\_ANY} & Attende per un figlio qualsiasi, usata in
questa maniera senza specificare nessuna opzione
è equivalente a \func{wait}.\\
- $ 0$&\const{WAIT\_MYPGRP}&attende per un figlio il cui
+ $ 0$&\const{WAIT\_MYPGRP}&Attende per un figlio il cui
\itindex{process~group} \textit{process group}
(vedi sez.~\ref{sec:sess_proc_group}) è
uguale a quello del processo chiamante. \\
- $>0$& -- & attende per un figlio il cui \acr{pid} è uguale
+ $>0$& -- & Attende per un figlio il cui \acr{pid} è uguale
al valore di \param{pid}.\\
\hline
\end{tabular}
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
- thread, che riprenderemo in sez.~\ref{sec:thread_xxx}.} che possono essere
-combinati fra loro con un OR aritmetico.
+ \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
\textbf{Macro} & \textbf{Descrizione}\\
\hline
\hline
- \const{WNOHANG} & la funzione ritorna immediatamente anche se non è
+ \const{WNOHANG} & La funzione ritorna immediatamente anche se non è
terminato nessun processo figlio. \\
- \const{WUNTRACED} & ritorna anche se un processo figlio è stato fermato. \\
- \const{WCONTINUED}& ritorna anche quando un processo figlio che era stato
+ \const{WUNTRACED} & Ritorna anche se un processo figlio è stato fermato. \\
+ \const{WCONTINUED}& Ritorna anche quando un processo figlio che era stato
fermato ha ripreso l'esecuzione.\footnotemark \\
\hline
\end{tabular}
\textbf{Macro} & \textbf{Descrizione}\\
\hline
\hline
- \macro{WIFEXITED(s)} & condizione vera (valore non nullo) per un processo
+ \macro{WIFEXITED(s)} & Condizione vera (valore non nullo) per un processo
figlio che sia terminato normalmente. \\
- \macro{WEXITSTATUS(s)} & restituisce gli otto bit meno significativi dello
+ \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 \val{WIFEXITED} ha restituito un valore non
nullo.\\
- \macro{WIFSIGNALED(s)} & condizione vera se il processo figlio è terminato
+ \macro{WIFSIGNALED(s)} & Condizione vera se il processo figlio è terminato
in maniera anomala a causa di un segnale che non
è stato catturato (vedi
sez.~\ref{sec:sig_notification}).\\
- \macro{WTERMSIG(s)} & restituisce il numero del segnale che ha causato
+ \macro{WTERMSIG(s)} & Restituisce il numero del segnale che ha causato
la terminazione anomala del processo; può essere
valutata solo se \val{WIFSIGNALED} ha restituito
un valore non nullo.\\
- \macro{WCOREDUMP(s)} & vera se il processo terminato ha generato un
+ \macro{WCOREDUMP(s)} & Vera se il processo terminato ha generato un
file di \itindex{core~dump} \textit{core
dump}; può essere valutata solo se
\val{WIFSIGNALED} ha restituito un valore non
nullo.\footnotemark \\
- \macro{WIFSTOPPED(s)} & vera se il processo che ha causato il ritorno di
+ \macro{WIFSTOPPED(s)} & Vera se il processo che ha causato il ritorno di
\func{waitpid} è bloccato; l'uso è possibile solo
con \func{waitpid} avendo specificato l'opzione
\const{WUNTRACED}.\\
- \macro{WSTOPSIG(s)} & restituisce il numero del segnale che ha bloccato
+ \macro{WSTOPSIG(s)} & Restituisce il numero del segnale che ha bloccato
il processo; può essere valutata solo se
\val{WIFSTOPPED} ha restituito un valore non
nullo. \\
- \macro{WIFCONTINUED(s)}& vera se il processo che ha causato il ritorno è
+ \macro{WIFCONTINUED(s)}& Vera se il processo che ha causato il ritorno è
stato riavviato da un
\const{SIGCONT}.\footnotemark \\
\hline
\textbf{Macro} & \textbf{Descrizione}\\
\hline
\hline
- \const{P\_PID} & indica la richiesta di attendere per un processo figlio
+ \const{P\_PID} & Indica la richiesta di attendere per un processo figlio
il cui \acr{pid} corrisponda al valore dell'argomento
\param{id}.\\
- \const{P\_PGID}& indica la richiesta di attendere per un processo figlio
+ \const{P\_PGID}& Indica la richiesta di attendere per un processo figlio
appartenente al \textit{process group} (vedi
sez.~\ref{sec:sess_proc_group}) il cui \acr{pgid}
corrisponda al valore dell'argomento \param{id}.\\
- \const{P\_ALL} & indica la richiesta di attendere per un processo figlio
+ \const{P\_ALL} & Indica la richiesta di attendere per un processo figlio
generico, il valore dell'argomento \param{id} viene
ignorato.\\
\hline
\textbf{Macro} & \textbf{Descrizione}\\
\hline
\hline
- \const{WEXITED} & ritorna quando un processo figlio è terminato. \\
- \const{WNOHANG} & ritorna immediatamente anche se non c'è niente da
- notificare. \\
- \const{WSTOPPED} & ritorna quando un processo figlio è stato fermato. \\
- \const{WCONTINUED}& ritorna quando un processo figlio che era stato
- fermato ha ripreso l'esecuzione. \\
- \const{WNOWAIT} & lascia il processo ancora in attesa di ricezione, così
+ \const{WEXITED} & Ritorna quando un processo figlio è terminato.\\
+ \const{WNOHANG} & Ritorna immediatamente anche se non c'è niente da
+ notificare.\\
+ \const{WSTOPPED} & Ritorna quando un processo figlio è stato fermato.\\
+ \const{WCONTINUED}& Ritorna quando un processo figlio che era stato
+ fermato ha ripreso l'esecuzione.\\
+ \const{WNOWAIT} & Lascia il processo ancora in attesa di ricezione, così
che una successiva chiamata possa di nuovo riceverne
- lo stato. \\
+ lo stato.\\
\hline
\end{tabular}
\caption{Costanti che identificano i bit dell'argomento \param{options}
senza che nessun figlio sia terminato. Pertanto per verificare il motivo del
ritorno della funzione occorre analizzare le informazioni che essa
restituisce; queste, al contrario delle precedenti \func{wait} e
-\func{waitpid}, sono ritornate nella struttura di tipo \struct{siginfo\_t}
-(vedi fig.~\ref{fig:sig_siginfo_t}) all'indirizzo puntato dall'argomento
-\param{infop}.
-
-Tratteremo nei dettagli questa struttura ed il significato dei suoi vari campi
-in sez.~\ref{sec:sig_sigaction}, per quanto ci interessa qui basta dire che al
-ritorno di \func{waitid} verranno avvalorati i seguenti campi:
+\func{waitpid} che usavano un semplice valore numerico, sono ritornate in una
+struttura di tipo \struct{siginfo\_t} (vedi fig.~\ref{fig:sig_siginfo_t})
+all'indirizzo puntato dall'argomento \param{infop}.
+
+Tratteremo nei dettagli la struttura \struct{siginfo\_t} ed il significato dei
+suoi vari campi in sez.~\ref{sec:sig_sigaction}, per quanto ci interessa qui
+basta dire che al ritorno di \func{waitid} verranno avvalorati i seguenti
+campi:
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\var{si\_pid}] con il \acr{pid} del figlio.
\item[\var{si\_uid}] con l'user-ID reale (vedi sez.~\ref{sec:proc_perms}) del
\const{CLD\_STOPPED}, \const{CLD\_CONTINUED} (vedi tab.~\ref{xxx_si_code}).
\end{basedescript}
-%TODO mettere riferimento alla tabella giusta
+%TODO mettere riferimento alla tabella giusta (vedere man credentials e man
+% waitid)
Infine Linux, seguendo un'estensione di BSD, supporta altre due funzioni per
la lettura dello stato di terminazione di un processo, analoghe alle
precedenti ma che prevedono un ulteriore argomento attraverso il quale il
-kernel può restituire al padre informazioni sulle risorse usate dal processo
-terminato e dai vari figli. Le due funzioni sono \funcd{wait3} e
-\funcd{wait4}, che diventano accessibili definendo la macro
-\macro{\_USE\_BSD}; i loro prototipi sono:
+kernel può restituire al padre informazioni sulle risorse (vedi
+sez.~\ref{sec:sys_res_limits}) usate dal processo terminato e dai vari figli.
+Le due funzioni sono \funcd{wait3} e \funcd{wait4}, che diventano accessibili
+definendo la macro \macro{\_USE\_BSD}; i loro prototipi sono:
\begin{functions}
\headdecl{sys/times.h} \headdecl{sys/types.h} \headdecl{sys/wait.h}
\headdecl{sys/resource.h}
sez.~\ref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
processo; la sua definizione è riportata in fig.~\ref{fig:sys_rusage_struct}.
-\subsection{Le funzioni \func{exec}}
+\subsection{La funzione \func{exec} e le funzioni di esecuzione dei programmi}
\label{sec:proc_exec}
Abbiamo già detto che una delle modalità principali con cui si utilizzano i
Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da
\func{exec} assume anche una serie di altre proprietà del processo chiamante;
la lista completa è la seguente:
-\begin{itemize*}
+\begin{itemize}
\item il \textit{process id} (\acr{pid}) ed il \textit{parent process id}
(\acr{ppid});
\item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i
\item il tempo restante ad un allarme (vedi sez.~\ref{sec:sig_alarm_abort});
\item la directory radice e la directory di lavoro corrente (vedi
sez.~\ref{sec:file_work_dir});
-\item la maschera di creazione dei file (\var{umask}, vedi
+\item la maschera di creazione dei file \itindex{umask} (\textit{umask}, vedi
sez.~\ref{sec:file_perm_management}) ed i \textit{lock} sui file (vedi
sez.~\ref{sec:file_locking});
\item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit});
\item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
\var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times}).
-\end{itemize*}
+\end{itemize}
Inoltre i segnali che sono stati impostati per essere ignorati nel processo
chiamante mantengono la stessa impostazione pure nel nuovo programma, tutti
impostato vengono chiusi, tutti gli altri file restano aperti. Questo
significa che il comportamento predefinito è che i file restano aperti
attraverso una \func{exec}, a meno di una chiamata esplicita a \func{fcntl}
-che imposti il suddetto flag.
-
-Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse
-attraverso una \func{exec}, in genere questo è fatto dalla funzione
-\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola
-l'impostazione del flag di \itindex{close-on-exec} \textit{close-on-exec}
-sulle directory che apre, in maniera trasparente all'utente.
+che imposti il suddetto flag. Per le directory, lo standard POSIX.1 richiede
+che esse vengano chiuse attraverso una \func{exec}, in genere questo è fatto
+dalla funzione \func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua
+da sola l'impostazione del flag di \itindex{close-on-exec}
+\textit{close-on-exec} sulle directory che apre, in maniera trasparente
+all'utente.
Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale}
-restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per
-l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il significato
-di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne
-quando il file che si va ad eseguire abbia o il \itindex{suid~bit} \acr{suid}
-bit o lo \itindex{sgid~bit} \acr{sgid} bit impostato, in questo caso
-l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} vengono
-impostati rispettivamente all'utente o al gruppo cui il file appartiene (per i
-dettagli vedi sez.~\ref{sec:proc_perms}).
+restano gli stessi all'esecuzione di \func{exec}; normalmente vale lo stesso
+anche per l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il
+significato di questi identificatori è trattato in
+sez.~\ref{sec:proc_access_id}), tranne quando il file di cui viene chiesta
+l'esecuzione ha o il \itindex{suid~bit} \acr{suid} bit o lo \itindex{sgid~bit}
+\acr{sgid} bit impostato, in questo caso l'\textsl{user-ID effettivo} ed il
+\textsl{group-ID effettivo} vengono impostati rispettivamente all'utente o al
+gruppo cui il file appartiene (per i dettagli di questo comportamento si veda
+sez.~\ref{sec:proc_perms}).
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. Se il programma è in formato ELF per caricare le librerie
-dinamiche viene usato l'interprete indicato nel segmento \const{PT\_INTERP},
-in genere questo è \file{/lib/ld-linux.so.1} per programmi collegati con le
-\acr{libc5}, e \file{/lib/ld-linux.so.2} per programmi collegati con le
-\acr{glibc}.
+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 le \acr{libc5}, e \sysfile{/lib/ld-linux.so.2} per programmi
+collegati con le \acr{glibc}.
Infine nel caso il file sia uno script esso deve iniziare con una linea nella
forma \cmd{\#!/path/to/interpreter [argomenti]} dove l'interprete indicato
lunga restituisce un errore di \const{ENAMETOOLONG}, una comparazione dei
vari comportamenti si trova su
\href{http://www.in-ulm.de/~mascheck/various/shebang/}
- {\texttt{http://www.in-ulm.de/\tild mascheck/various/shebang/}}.}
+ {\textsf{http://www.in-ulm.de/\tild mascheck/various/shebang/}}.}
Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è
basata la gestione dei processi in Unix: con \func{fork} si crea un nuovo
realtà già esistono estensioni di questo modello base, che lo rendono più
flessibile e controllabile, come le \itindex{capabilities}
\textit{capabilities} illustrate in sez.~\ref{sec:proc_capabilities}, le ACL
- per i file o il \itindex{Mandatory~Access~Control~(MAC)} \textit{Mandatory
- Access Control} di SELinux; inoltre basandosi sul lavoro effettuato con
+ per i file (vedi sez.~\ref{sec:file_ACL}) o il
+ \itindex{Mandatory~Access~Control~(MAC)} \textit{Mandatory Access Control}
+ di \index{SELinux} SELinux; inoltre basandosi sul lavoro effettuato con
SELinux, a partire dal kernel 2.5.x, è iniziato lo sviluppo di una
- infrastruttura di sicurezza, il \textit{Linux Security Modules}, o LSM, in
- grado di fornire diversi agganci a livello del kernel per modularizzare
- tutti i possibili controlli di accesso.} di sicurezza di un sistema
-unix-like è fondato sui concetti di utente e gruppo, e sulla separazione fra
-l'amministratore (\textsl{root}, detto spesso anche \textit{superuser}) che
-non è sottoposto a restrizioni, ed il resto degli utenti, per i quali invece
-vengono effettuati i vari controlli di accesso.
+ infrastruttura di sicurezza, i \itindex{Linux~Security~Modules}
+ \textit{Linux Security Modules}, o LSM, in grado di fornire diversi agganci
+ a livello del kernel per modularizzare tutti i possibili controlli di
+ accesso.} di sicurezza di un sistema unix-like è fondato sui concetti di
+utente e gruppo, e sulla separazione fra l'amministratore (\textsl{root},
+detto spesso anche \textit{superuser}) che non è sottoposto a restrizioni, ed
+il resto degli utenti, per i quali invece vengono effettuati i vari controlli
+di accesso.
Abbiamo già accennato come il sistema associ ad ogni utente e gruppo due
identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per
\hline
\hline
\acr{uid} & \textit{real} & \textsl{user-ID reale}
- & indica l'utente che ha lanciato il programma\\
+ & Indica l'utente che ha lanciato il programma.\\
\acr{gid} & '' &\textsl{group-ID reale}
- & indica il gruppo principale dell'utente che ha lanciato
- il programma \\
+ & Indica il gruppo principale dell'utente che ha lanciato
+ il programma.\\
\hline
\acr{euid} & \textit{effective} &\textsl{user-ID effettivo}
- & indica l'utente usato nel controllo di accesso \\
+ & Indica l'utente usato nel controllo di accesso.\\
\acr{egid} & '' & \textsl{group-ID effettivo}
- & indica il gruppo usato nel controllo di accesso \\
+ & Indica il gruppo usato nel controllo di accesso.\\
-- & -- & \textsl{group-ID supplementari}
- & indicano gli ulteriori gruppi cui l'utente appartiene \\
+ & Indicano gli ulteriori gruppi cui l'utente appartiene.\\
\hline
-- & \textit{saved} & \textsl{user-ID salvato}
- & è una copia dell'\acr{euid} iniziale\\
+ & È una copia dell'\acr{euid} iniziale.\\
-- & '' & \textsl{group-ID salvato}
- & è una copia dell'\acr{egid} iniziale \\
+ & È una copia dell'\acr{egid} iniziale.\\
\hline
\acr{fsuid} & \textit{filesystem} &\textsl{user-ID di filesystem}
- & indica l'utente effettivo per l'accesso al filesystem \\
+ & Indica l'utente effettivo per l'accesso al filesystem. \\
\acr{fsgid} & '' & \textsl{group-ID di filesystem}
- & indica il gruppo effettivo per l'accesso al filesystem \\
+ & Indica il gruppo effettivo per l'accesso al filesystem.\\
\hline
\end{tabular}
\caption{Identificatori di utente e gruppo associati a ciascun processo con
ed eventualmente tornare indietro.
Come esempio per chiarire l'uso di queste funzioni prendiamo quello con cui
-viene gestito l'accesso al file \file{/var/log/utmp}. In questo file viene
+viene gestito l'accesso al file \sysfile{/var/log/utmp}. In questo file viene
registrato chi sta usando il sistema al momento corrente; chiaramente non può
essere lasciato aperto in scrittura a qualunque utente, che potrebbe
falsificare la registrazione. Per questo motivo questo file (e l'analogo
-\file{/var/log/wtmp} su cui vengono registrati login e logout) appartengono ad
-un gruppo dedicato (\acr{utmp}) ed i programmi che devono accedervi (ad
+\sysfile{/var/log/wtmp} su cui vengono registrati login e logout) appartengono
+ad un gruppo dedicato (\acr{utmp}) ed i programmi che devono accedervi (ad
esempio tutti i programmi di terminale in X, o il programma \cmd{screen} che
crea terminali multipli su una console) appartengono a questo gruppo ed hanno
il bit \acr{sgid} impostato.
\textsl{group-ID salvato} &=& \textrm{\acr{utmp}}
\end{eqnarray*}
in questo modo, dato che il \textsl{group-ID effettivo} è quello giusto, il
-programma può accedere a \file{/var/log/utmp} in scrittura ed aggiornarlo. A
-questo punto il programma può eseguire una \code{setgid(getgid())} per
+programma può accedere a \sysfile{/var/log/utmp} in scrittura ed aggiornarlo.
+A questo punto il programma può eseguire una \code{setgid(getgid())} per
impostare il \textsl{group-ID effettivo} a quello dell'utente (e dato che il
\textsl{group-ID reale} corrisponde la funzione avrà successo), in questo modo
non sarà possibile lanciare dal terminale programmi che modificano detto file,
\end{eqnarray*}
e ogni processo lanciato dal terminale avrebbe comunque \acr{gid} come
\textsl{group-ID effettivo}. All'uscita dal terminale, per poter di nuovo
-aggiornare lo stato di \file{/var/log/utmp} il programma eseguirà una
+aggiornare lo stato di \sysfile{/var/log/utmp} il programma eseguirà una
\code{setgid(utmp)} (dove \var{utmp} è il valore numerico associato al gruppo
\acr{utmp}, ottenuto ad esempio con una precedente \func{getegid}), dato che
in questo caso il valore richiesto corrisponde al \textsl{group-ID salvato} la
\textsl{group-ID effettivo} &=& \textrm{\acr{utmp}} \\
\textsl{group-ID salvato} &=& \textrm{\acr{utmp} (invariato)}
\end{eqnarray*}
-consentendo l'accesso a \file{/var/log/utmp}.
+consentendo l'accesso a \sysfile{/var/log/utmp}.
Occorre però tenere conto che tutto questo non è possibile con un processo con
i privilegi di amministratore, in tal caso infatti l'esecuzione di una
\end{functions}
La funzione esegue la scansione del database dei gruppi (usualmente
-\file{/etc/groups}) cercando i gruppi di cui è membro l'utente \param{user}
+\conffile{/etc/group}) cercando i gruppi di cui è membro l'utente \param{user}
con cui costruisce una lista di gruppi supplementari, a cui aggiunge anche
\param{group}, infine imposta questa lista per il processo corrente usando
\func{setgroups}. Si tenga presente che sia \func{setgroups} che
ma non essendo implementata non ne tratteremo qui.} in modo da poter
stabilire quali capacità possono essere utilizzate quando viene messo in
esecuzione uno specifico programma; attualmente però questa funzionalità non è
-implementata.\footnote{per attualmente si intende fino al kernel 2.6.13, e
- finora non è disponibile al momento neanche presente nessuna realizzazione
- sperimentale delle specifiche POSIX.1e, anche se esistono dei patch di
- sicurezza del kernel, come LIDS (vedi
- \href{http://www.lids.org}{\texttt{http://www.lids.org/})} che realizzano
- qualcosa di simile.}
+implementata.\footnote{per attualmente si intende fino al kernel 2.6.23;
+ benché l'infrastruttura per crearla sia presente (vedi anche
+ sez.~\ref{sec:file_xattr}) finora non è disponibile nessuna realizzazione
+ delle specifiche POSIX.1e, esistono però dei patch di sicurezza del kernel,
+ come LIDS (vedi \href{http://www.lids.org}{\textsf{http://www.lids.org/})}
+ che realizzano qualcosa di simile.}
+% TODO verificare per process capability bounding set, vedi:
+% http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b7391de67da515c91f48aa371de77cb6cc5c07e
+
+% TODO capire cosa cambia con i patch del 2.6.26, vedi
+% http://lwn.net/Articles/280279/
\begin{table}[!h!bt]
\centering
%
% POSIX-draft defined capabilities.
%
- \const{CAP\_CHOWN} & la capacità di cambiare proprietario e gruppo
+ \const{CAP\_CHOWN} & La capacità di cambiare proprietario e gruppo
proprietario di un file (vedi
sez.~\ref{sec:file_ownership_management}).\\
- \const{CAP\_DAC\_OVERRIDE}& la capacità di evitare il controllo dei
+ \const{CAP\_DAC\_OVERRIDE}& La capacità di evitare il controllo dei
permessi di lettura, scrittura ed esecuzione dei
file, (vedi sez.~\ref{sec:file_access_control})
caratteristici del modello classico del
\itindex{Discrectionary~Access~Control~(DAC)}
\textit{Discrectionary Access Control} (da cui
il nome DAC).\\
- \const{CAP\_DAC\_READ\_SEARCH}& la capacità di evitare il controllo dei
+ \const{CAP\_DAC\_READ\_SEARCH}& La capacità di evitare il controllo dei
permessi di lettura, scrittura ed esecuzione per
le directory (vedi
sez.~\ref{sec:file_access_control}).\\
- \const{CAP\_FOWNER} & la capacità di evitare il controllo che
+ \const{CAP\_FOWNER} & La capacità di evitare il controllo che
l'user-ID effettivo del processo (o meglio il
\textit{filesystem user-ID}, vedi
sez.~\ref{sec:proc_setuid}) coincida con
\func{open} e \func{fcntl} (vedi
sez.~\ref{sec:file_open} e
sez.~\ref{sec:file_fcntl}).\\
- \const{CAP\_FSETID} & la capacità di evitare la cancellazione
+ \const{CAP\_FSETID} & La capacità di evitare la cancellazione
automatica dei bit \itindex{suid~bit} \acr{suid}
e \itindex{sgid~bit} \acr{sgid} quando un file
per i quali sono impostati viene modificato da
quando questo è relativo ad un gruppo cui non si
appartiene (vedi
sez.~\ref{sec:file_perm_management}).\\
- \const{CAP\_KILL} & la capacità di mandare segnali a qualunque
+ \const{CAP\_KILL} & La capacità di mandare segnali a qualunque
processo (vedi sez.~\ref{sec:sig_kill_raise}).\\
- \const{CAP\_SETGID} & la capacità di manipolare i group ID dei
+ \const{CAP\_SETGID} & La capacità di manipolare i group ID dei
processi, sia il principale che i supplementari,
(vedi sez.~\ref{sec:proc_setgroups} che quelli
trasmessi tramite i socket \textit{unix domain}
(vedi sez.~\ref{sec:unix_socket}).\\
- \const{CAP\_SETUID} & la capacità di manipolare gli user ID del
+ \const{CAP\_SETUID} & La capacità di manipolare gli user ID del
processo (con \func{setuid}, \func{setreuid},
\func{setresuid}, \func{setfsuid}) e di
trasmettere un valore arbitrario
% Linux specific capabilities
%
\hline
- \const{CAP\_SETPCAP} & la capacità di impostare o rimuovere una capacità
+ \const{CAP\_SETPCAP} & La capacità di impostare o rimuovere una capacità
(limitatamente a quelle che il processo
chiamante ha nel suo insieme di capacità
permesse) da qualunque processo.\\
- \const{CAP\_LINUX\_IMMUTABLE}& la capacità di impostare gli attributi
+% TODO cambiata nel 2.4.24 rc1 ?
+ \const{CAP\_LINUX\_IMMUTABLE}& La capacità di impostare gli attributi
\textit{immutable} e \itindex{append~mode}
\textit{append only} per i file su un
filesystem che supporta questi
attributi estesi.\\
- \const{CAP\_NET\_BIND\_SERVICE}& la capacità di porre in ascolto server
+ \const{CAP\_NET\_BIND\_SERVICE}& La capacità di porre in ascolto server
su porte riservate (vedi
sez.~\ref{sec:TCP_func_bind}).\\
- \const{CAP\_NET\_BROADCAST}& la capacità di consentire l'uso di socket in
+ \const{CAP\_NET\_BROADCAST}& La capacità di consentire l'uso di socket in
\itindex{broadcast} \textit{broadcast} e
\itindex{multicast} \textit{multicast}.\\
- \const{CAP\_NET\_ADMIN} & la capacità di eseguire alcune operazioni
+ \const{CAP\_NET\_ADMIN} & La capacità di eseguire alcune operazioni
privilegiate sulla rete (impostare le opzioni
privilegiate dei socket, abilitare il
\itindex{multicast} \textit{multicasting},
impostare interfacce di rete e
tabella di instradamento).\\
- \const{CAP\_NET\_RAW} & la capacità di usare socket \texttt{RAW} e
+ \const{CAP\_NET\_RAW} & La capacità di usare socket \texttt{RAW} e
\texttt{PACKET} (quelli che permettono di creare
pacchetti nei protocolli di basso livello).\\
- \const{CAP\_IPC\_LOCK} & la capacità di effettuare il \textit{memory
+ \const{CAP\_IPC\_LOCK} & La capacità di effettuare il \textit{memory
locking} \itindex{memory~locking} con le
funzioni \func{mlock}, \func{mlockall},
\func{shmctl}, \func{mmap} (vedi
sez.~\ref{sec:proc_mem_lock} e
sez.~\ref{sec:file_memory_map}). \\
- \const{CAP\_IPC\_OWNER} & la capacità di evitare il controllo dei permessi
+ \const{CAP\_IPC\_OWNER} & La capacità di evitare il controllo dei permessi
per le operazioni sugli oggetti di
intercomunicazione fra processi (vedi
sez.~\ref{sec:ipc_sysv}).\\
- \const{CAP\_SYS\_MODULE}& la capacità di caricare e rimuovere moduli del
+ \const{CAP\_SYS\_MODULE}& La capacità di caricare e rimuovere moduli del
kernel. \\
- \const{CAP\_SYS\_RAWIO} & la capacità di eseguire operazioni sulle porte
+ \const{CAP\_SYS\_RAWIO} & La capacità di eseguire operazioni sulle porte
di I/O con \func{ioperm} e \func{iopl} (vedi
sez.~\ref{sec:file_io_port}).\\
- \const{CAP\_SYS\_CHROOT}& la capacità di eseguire la funzione
+ \const{CAP\_SYS\_CHROOT}& La capacità di eseguire la funzione
\func{chroot} (vedi
sez.~\ref{sec:file_chroot}).\\
- \const{CAP\_SYS\_PTRACE}& consente di tracciare qualunque processo con
+ \const{CAP\_SYS\_PTRACE}& Consente di tracciare qualunque processo con
\func{ptrace} (vedi
sez.~\ref{sec:xxx_ptrace}).\\
-% TODO documentatare ptrace
- \const{CAP\_SYS\_PACCT} & la capacità di usare le funzioni di
+ \const{CAP\_SYS\_PACCT} & La capacità di usare le funzioni di
\textit{accounting} dei processi (vedi
sez.~\ref{sec:sys_bsd_accounting}).\\
- \const{CAP\_SYS\_ADMIN} & la capacità di eseguire una serie di compiti
+ \const{CAP\_SYS\_ADMIN} & La capacità di eseguire una serie di compiti
amministrativi (come impostare le quote,
attivare e disattivare la swap, montare,
rimontare e smontare filesystem, ecc.). \\
- \const{CAP\_SYS\_BOOT} & la capacità di fare eseguire un riavvio del
+ \const{CAP\_SYS\_BOOT} & La capacità di fare eseguire un riavvio del
sistema.\\
- \const{CAP\_SYS\_NICE} & la capacità di modificare le priorità dei
+ \const{CAP\_SYS\_NICE} & La capacità di modificare le priorità dei
processi (vedi sez.~\ref{sec:proc_priority}). \\
- \const{CAP\_SYS\_RESOURCE}& la capacità di superare le limitazioni sulle
+ \const{CAP\_SYS\_RESOURCE}& La capacità di superare le limitazioni sulle
risorse, aumentare le quote disco, usare lo
spazio disco riservato all'amministratore.\\
- \const{CAP\_SYS\_TIME} & la capacità di modificare il tempo di sistema
+ \const{CAP\_SYS\_TIME} & La capacità di modificare il tempo di sistema
(vedi sez.~\ref{sec:sys_time}).\\
- \const{CAP\_SYS\_TTY\_CONFIG}& la capacità di simulare un \textit{hangup}
+ \const{CAP\_SYS\_TTY\_CONFIG}& La capacità di simulare un \textit{hangup}
della console, con la funzione
\func{vhangup}.\\
- \const{CAP\_MKNOD} & la capacità di creare file di dispositivo con la
+ \const{CAP\_MKNOD} & La capacità di creare file di dispositivo con la
funzione \func{mknod} (vedi
sez.~\ref{sec:file_mknod}).\footnotemark\\
- \const{CAP\_LEASE} & la capacità di creare dei \textit{file lease}
+ \const{CAP\_LEASE} & La capacità di creare dei \textit{file lease}
\index{file!lease} su di un file (vedi
sez.~\ref{sec:file_asyncronous_lease})
indipendentemente dalla proprietà dello
stesso.\footnotemark\\
- \const{CAP\_SETFCAP} & la capacità di impostare le
+ \const{CAP\_SETFCAP} & La capacità di impostare le
\textit{capabilities} di un file (non
supportata).\\
\hline
capacità in esso elencate.
Il \textit{capabilities bounding set} è un parametro di sistema, accessibile
-attraverso il contenuto del file \file{/proc/sys/kernel/cap-bound}, che per
+attraverso il contenuto del file \procfile{/proc/sys/kernel/cap-bound}, che per
questa sua caratteristica consente di impostare un limite generale alle
capacità che possono essere accordate ai vari processi. Questo valore può
essere impostato ad un valore arbitrario esclusivamente dal primo processo
\func{capget} e \func{capset}, sono soggette ad essere modificate con il
cambiamento del kernel (in particolare i tipi di dati delle strutture) ed
anche se finora l'interfaccia è risultata stabile, non c'è nessuna
-assicurazione che questa venga mantenuta. Pertanto se si vogliono scrivere
-programmi portabili che possano essere eseguiti su qualunque versione del
-kernel è opportuno utilizzare le interfacce di alto livello.
+assicurazione che questa venga mantenuta.\footnote{anzi, visto lo scarso
+ utilizzo di questa funzionalità ci sono state varie discussioni fra gli
+ sviluppatori del kernel relative all'eliminarla o al modificarla
+ radicalmente.} Pertanto se si vogliono scrivere programmi portabili che
+possano essere eseguiti su qualunque versione del kernel è opportuno
+utilizzare le interfacce di alto livello.
\begin{figure}[!htb]
\footnotesize
non c'è memoria sufficiente ad allocare i dati) viene restituito \macro{NULL}
ed \var{errno} viene impostata a \errval{ENOMEM}. La memoria necessaria a
mantenere i dati viene automaticamente allocata da \func{cap\_init}, ma dovrà
-essere disallocata esplicitamente quando non più necessaria utilizzando la
-funzione \funcd{cap\_free}, il cui prototipo è:
+essere disallocata esplicitamente quando non è più necessaria utilizzando, per
+questo l'interfaccia fornisce una apposita funzione, \funcd{cap\_free}, il cui
+prototipo è:
\begin{functions}
\headdecl{sys/capability.h}
della libreria sia per un \textit{capability state}, nel qual caso l'argomento
dovrà essere un dato di tipo \type{cap\_t}, che per una descrizione testuale
dello stesso,\footnote{cioè quanto ottenuto tramite la funzione
- \func{cap\_to\_text}.} nel qual caso l'argomento dovrà essere di tipo
-\texttt{char *}. L'argomento \param{obj\_d} deve corrispondere ad un oggetto
-ottenuto tramite altre funzioni della libreria, altrimenti la funzione fallirà
-con un errore di \errval{EINVAL}.
+ \func{cap\_to\_text}.} nel qual caso l'argomento dovrà essere un dato di
+tipo \texttt{char *}. Per questo l'argomento \param{obj\_d} è dichiarato come
+\texttt{void *} e deve sempre corrispondere ad un puntatore ottenuto tramite
+le altre funzioni della libreria, altrimenti la funzione fallirà con un errore
+di \errval{EINVAL}.
Infine si può creare una copia di un \textit{capability state} ottenuto in
precedenza tramite la funzione \funcd{cap\_dup}, il cui prototipo è:
copia, che conterrà gli stessi valori delle \textit{capabilities} presenti
nell'originale. La memoria necessaria viene allocata automaticamente dalla
funzione. Una volta effettuata la copia i due \textit{capability state}
-potranno essere modificati in maniera completamente indipendente.
+potranno essere modificati in maniera completamente
+indipendente.\footnote{alla fine delle operazioni si ricordi però di
+ disallocare anche la copia, oltre all'originale. }
-Una seconda classe di funzioni di servizio sono quelle per la gestione dei
-dati contenuti all'interno di un \textit{capability state}; la prima di esse è
-\funcd{cap\_clear}, il cui prototipo è:
+Una seconda classe di funzioni di servizio previste dall'interfaccia sono
+quelle per la gestione dei dati contenuti all'interno di un \textit{capability
+ state}; la prima di queste è \funcd{cap\_clear}, il cui prototipo è:
\begin{functions}
\headdecl{sys/capability.h}
\type{cap\_value\_t} deve indicare una sola capacità.\footnote{nel file di
header citato nella nota precedente il tipo \type{cap\_value\_t} è definito
come \ctyp{int}, ma i valori validi sono soltanto quelli di
- tab.~\ref{tab:proc_capabilities}.} Infine lo stato di una capacità è
-descritto ad una variabile di tipo \type{cap\_flag\_value\_t}, che a sua volta
-può assumere soltanto uno\footnote{anche questo è un tipo enumerato.} dei
-valori di tab.~\ref{tab:cap_value_type}.
+ tab.~\ref{tab:proc_capabilities}.}
+
+Infine lo stato di una capacità è descritto ad una variabile di tipo
+\type{cap\_flag\_value\_t}, che a sua volta può assumere soltanto
+uno\footnote{anche questo è un tipo enumerato.} dei valori di
+tab.~\ref{tab:cap_value_type}.
\begin{table}[htb]
\centering
stato di una capacità alla volta.
La funzione \func{cap\_set\_flag} può invece impostare in una sola chiamata
-più capacità, anche se solo all'interno dello stesso insieme; per questo essa
-prende un vettore di valori di tipo \type{cap\_value\_t} nell'argomento
-\param{caps}, la cui dimensione è specificata dall'argomento \param{ncap}. Il
-tipo di impostazione da eseguire (cancellazione o impostazione) viene indicato
-dall'argomento \param{value}.
+più \textit{capabilities}, anche se solo all'interno dello stesso insieme. Per
+questo motivo essa prende un vettore di valori di tipo \type{cap\_value\_t}
+nell'argomento \param{caps}, la cui dimensione viene specificata dall'argomento
+\param{ncap}. Il tipo di impostazione da eseguire (cancellazione o
+impostazione) viene indicato dall'argomento \param{value}.
Per la visualizzazione dello stato delle \textit{capabilities} l'interfaccia
prevede una funzione apposita, \funcd{cap\_to\_text}, il cui prototipo è:
come argomento, e, qualora l'argomento \param{length\_p} sia diverso da
\val{NULL}, restituisce nella variabile intera da questo puntata la lunghezza
della stringa. La stringa restituita viene allocata automaticamente dalla
-funzione e deve essere liberata con \func{cap\_free}.
+funzione e pertanto dovrà essere liberata con \func{cap\_free}.
-Fin quei abbiamo trattato delle funzioni di manipolazione dei
-\textit{capabilities state}; quando si vuole eseguire la lettura delle
-\textit{capabilities} del processo corrente si deve usare la funzione
-\funcd{cap\_get\_proc}, il cui prototipo è:
+Fin quei abbiamo trattato solo le funzioni di servizio relative alla
+manipolazione dei \textit{capabilities state}; l'interfaccia di gestione
+prevede però anche le funzioni per la gestione delle \textit{capabilities}
+stesse. La prima di queste è \funcd{cap\_get\_proc} che consente la lettura
+delle \textit{capabilities} del processo corrente, il suo prototipo è:
\begin{functions}
\headdecl{sys/capability.h}
assumere i valori \errval{EINVAL}, \errval{EPERM} o \errval{ENOMEM}. }
\end{functions}
-La funzione legge il valore delle \textit{capabilities} del processo corrente
-e restituisce il puntatore ad un \textit{capabilities state} contenente il
-risultato, che provvede ad allocare autonomamente, e che occorrerà liberare
-con \func{cap\_free} quando non sarà più utilizzato.
+La funzione legge il valore delle \textit{capabilities} associate al processo
+da cui viene invocata, restituendo il risultato tramite il puntatore ad un
+\textit{capabilities state} contenente tutti i dati che provvede ad allocare
+autonomamente e che di nuovo occorrerà liberare con \func{cap\_free} quando
+non sarà più utilizzato.
Se invece si vogliono leggere le \textit{capabilities} di un processo
specifico occorre usare la funzione \funcd{capgetp}, il cui
\errval{EPERM} o \errval{ENOMEM}.
}
\end{functions}
+%TODO controllare e correggere i codici di errore!!!
La funzione legge il valore delle \textit{capabilities} del processo indicato
-con l'argomento \param{pid}, salvando il risultato nel \textit{capabilities
- state} all'indirizzo \param{cap\_d} che deve essere stato creato in
-precedenza. Qualora il processo non esista si avrà un errore di
-\errval{ESRCH}. Gli stessi valori possono essere letti direttamente nel
-filesystem \textit{proc}, nei file \texttt{/proc/<pid>/status}; ad esempio per
-\texttt{init} si otterrà qualcosa del tipo:
+con l'argomento \param{pid}, e restituisce il risultato nel
+\textit{capabilities state} posto all'indirizzo indicato con l'argomento
+\param{cap\_d}; a differenza della precedente in questo caso il
+\textit{capability state} deve essere stato creato in precedenza. Qualora il
+processo indicato non esista si avrà un errore di \errval{ESRCH}. Gli stessi
+valori possono essere letti direttamente nel filesystem \textit{proc}, nei
+file \texttt{/proc/<pid>/status}; ad esempio per \texttt{init} si otterrà
+qualcosa del tipo:
\begin{Verbatim}
...
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff
+...
\end{Verbatim}
Infine per impostare le \textit{capabilities} del processo corrente (non
% TODO documentare prctl ...
+% TODO: rivedere alla luce degli aggiornamenti del 2.6 (man sched_setscheduler)
+
\section{La gestione della priorità di esecuzione}
\label{sec:proc_priority}
cui non esiste un meccanismo che sia valido per tutti gli usi.
La caratteristica specifica di un sistema multitasking come Linux è quella del
-cosiddetto \itindex{prehemptive~multitasking} \textit{prehemptive
+cosiddetto \itindex{preemptive~multitasking} \textit{preemptive
multitasking}: questo significa che al contrario di altri sistemi (che usano
invece il cosiddetto \itindex{cooperative~multitasking} \textit{cooperative
multitasking}) non sono i singoli processi, ma il kernel stesso a decidere
\label{tab:proc_proc_states}
\end{table}
+% TODO nel 2.6.25 è stato aggiunto TASK_KILLABLE, da capire dova va messo.
+
Si deve quindi tenere presente che l'utilizzo della CPU è soltanto una delle
risorse che sono necessarie per l'esecuzione di un programma, e a seconda
dello scopo del programma non è detto neanche che sia la più importante (molti
{int nice(int inc)}
Aumenta il valore di \var{nice} per il processo corrente.
- \bodydesc{La funzione ritorna zero in caso di successo e -1 in caso di
- errore, nel qual caso \var{errno} può assumere i valori:
+ \bodydesc{La funzione ritorna zero o il nuovo valore di \var{nice} in caso
+ di successo e -1 in caso di errore, nel qual caso \var{errno} può assumere
+ i valori:
\begin{errlist}
\item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha
specificato un valore di \param{inc} negativo.
l'amministratore può specificare valori negativi che permettono di aumentare
la priorità di un processo.
-In SUSv2 la funzione ritorna il nuovo valore di \var{nice}; Linux non segue
-questa convenzione, e per leggere il nuovo valore occorre invece usare la
-funzione \funcd{getpriority}, derivata da BSD, il cui prototipo è:
+Gli standard SUSv2 e POSIX.1 prevedono che la funzione ritorni il nuovo valore
+di \var{nice} del processo; tuttavia la system call di Linux non segue questa
+convenzione e restituisce sempre 0 in caso di successo, questo perché $-1$ è
+un valore di \var{nice} legittimo e questo comporta una confusione con una
+eventuale condizione di errore.
+
+Fino alle \acr{glibc} 2.2.4 la funzione di libreria riportava direttamente il
+valore ottenuto dalla system call, violando lo standard, per cui per ottenere
+il nuovo valore occorreva una successiva chiamata alla funzione
+\func{getpriority}. A partire dalla \acr{glibc} 2.2.4 \func{nice} è stata
+reimplementata come funzione di libreria, e restituisce il valore di
+\var{nice} come richiesto dallo standard.\footnote{questo viene fatto
+ chiamando al suo interno \func{getpriority}, ed è questo il motivo delle due
+ possibilità per i valori di ritorno citati nella descrizione del prototipo.}
+In questo caso l'unico modo per rilevare in maniera affidabile una condizione
+di errore è quello di azzerare \var{errno} prima della chiamata della funzione
+e verificarne il valore quando \func{nice} restituisce $-1$.
+
+
+Per leggere il valore di nice di un processo occorre usare la funzione
+\funcd{getpriority}, derivata da BSD; il suo prototipo è:
\begin{prototype}{sys/resource.h}
{int getpriority(int which, int who)}
\end{table}
La funzione restituisce la priorità più alta (cioè il valore più basso) fra
-quelle dei processi specificati; dato che -1 è un valore possibile, per poter
-rilevare una condizione di errore è necessario cancellare sempre \var{errno}
-prima della chiamata alla funzione, per verificare che essa resti uguale a
-zero.
+quelle dei processi specificati; di nuovo, dato che $-1$ è un valore
+possibile, per poter rilevare una condizione di errore è necessario cancellare
+sempre \var{errno} prima della chiamata alla funzione per verificare che essa
+resti uguale a zero.
-Analoga a \func{getpriority} la funzione \funcd{setpriority} permette di
+Analoga a \func{getpriority} è la funzione \funcd{setpriority} che permette di
impostare la priorità di uno o più processi; il suo prototipo è:
\begin{prototype}{sys/resource.h}
{int setpriority(int which, int who, int prio)}
vengono gestiti questi processi dipende dalla politica di scheduling che si è
scelta; lo standard ne prevede due:
\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}}
-\item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito
+\item[\textsf{FIFO}] \textit{First In First Out}. Il processo viene eseguito
fintanto che non cede volontariamente la CPU (con \func{sched\_yield}), si
blocca, finisce o viene interrotto da un processo a priorità più alta. Se il
processo viene interrotto da uno a priorità più alta esso resterà in cima
più alta diverranno inattivi. Se invece lo si blocca volontariamente sarà
posto in coda alla lista (ed altri processi con la stessa priorità potranno
essere eseguiti).
-\item[\textit{RR}] \textit{Round Robin}. Il comportamento è del tutto analogo
+\item[\textsf{RR}] \textit{Round Robin}. Il comportamento è del tutto analogo
a quello precedente, con la sola differenza che ciascun processo viene
eseguito al massimo per un certo periodo di tempo (la cosiddetta
\textit{time slice}) dopo di che viene automaticamente posto in fondo alla
\textbf{Policy} & \textbf{Significato} \\
\hline
\hline
- \const{SCHED\_FIFO} & Scheduling real-time con politica \textit{FIFO} \\
+ \const{SCHED\_FIFO} & Scheduling real-time con politica \textit{FIFO}. \\
\const{SCHED\_RR} & Scheduling real-time con politica \textit{Round
- Robin} \\
- \const{SCHED\_OTHER}& Scheduling ordinario\\
+ Robin}. \\
+ \const{SCHED\_OTHER}& Scheduling ordinario.\\
+ \const{SCHED\_BATCH}& Scheduling ordinario con l'assunzione ulteriore di
+ lavoro \textit{CPU intensive}.\footnotemark\\
\hline
\end{tabular}
\caption{Valori dell'argomento \param{policy} per la funzione
\label{tab:proc_sched_policy}
\end{table}
+\footnotetext{introdotto con il kernel 2.6.16.}
+
+% TODO manca SCHED_IDLE
+
Il valore della priorità è passato attraverso la struttura
\struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui
solo campo attualmente definito è \var{sched\_priority}, che nel caso delle
questa funzione ritorna sempre un valore di 150 millisecondi, e non importa
specificare il PID di un processo reale.
-
Come accennato ogni processo che usa lo scheduling real-time può rilasciare
volontariamente la CPU; questo viene fatto attraverso la funzione
\funcd{sched\_yield}, il cui prototipo è:
in modalità \textit{fifo}, per permettere l'esecuzione degli altri processi
con pari priorità quando la sezione più urgente è finita.
+% TODO: con il 2.6.23 il comportamento è stato leggermente modificato ed è
+% stato introdotto /proc/sys/kernel/sched_compat_yield da mettere a 1 per aver
+% la compatibilità con il precedente.
-\subsection{Il controllo dello \textit{scheduler} per i sistemi multiprocessore}
+\subsection{Il controllo dello \textit{scheduler} per i sistemi
+ multiprocessore}
\label{sec:proc_sched_multiprocess}
Infine con il supporto dei sistemi multiprocessore sono state introdotte delle
l'opportuna infrastruttura ed una nuova system call che permette di impostare
su quali processori far eseguire un determinato processo attraverso una
\textsl{maschera di affinità}. La corrispondente funzione di libreria è
-\funcd{sched\_setaffinity} ed il suo prototipo\footnote{di questa funzione (e
- della corrispondente \func{sched\_setaffinity}) esistono versioni diverse
- per gli argomenti successivi a \param{pid}: la prima (quella riportata nella
- pagina di manuale) prevedeva due ulteriori argomenti di tipo
- \texttt{unsigned int len} e \texttt{unsigned long *mask}, poi l'argomento
- \texttt{len} è stato eliminato, successivamente si è introdotta la versione
- riportata con però un secondo argomento di tipo \texttt{size\_t cpusetsize}
- (anche questa citata nella pagina di manuale); la versione citata è quella
- riportata nel manuale delle \textsl{glibc} e corrispondente alla definizione
- presente in \file{sched.h}.} è:
+\funcd{sched\_setaffinity} ed il suo prototipo è:
\begin{prototype}{sched.h}
- {int sched\_setaffinity (pid\_t pid, const cpu\_set\_t *cpuset)}
+ {int sched\_setaffinity (pid\_t pid, unsigned int cpusetsize, const
+ cpu\_set\_t *cpuset)}
Imposta la maschera di affinità del processo \param{pid}.
\bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
ed inoltre anche \errval{EFAULT}.}
\end{prototype}
+
+Questa funzione e la corrispondente \func{sched\_setaffinity} hanno una storia
+abbastanza complessa, la system call prevede l'uso di due ulteriori argomenti
+di tipo \texttt{unsigned int len} e \texttt{unsigned long *mask}, che
+corrispondono al fatto che la implementazione effettiva usa una semplice
+maschera binaria. Quando le funzioni vennero incluse nelle \acr{glibc}
+assunsero invece il prototipo appena mostrato. A complicare la cosa si
+aggiunge il fatto che nella versione 2.3.3 delle \acr{glibc} l'argomento
+\param{cpusetsize} è stato eliminato, per poi essere ripristinato nella
+versione 2.3.4.\footnote{pertanto se la vostra pagina di manuale non è
+ aggiornata, o usate quella particolare versione delle \acr{glibc}, potrete
+ trovare indicazioni diverse, il prototipo illustrato è quello riportato
+ nella versione corrente (maggio 2008) delle pagine di manuale e
+ corrispondente alla definizione presente in \file{sched.h}.}
+
La funzione imposta, con l'uso del valore contenuto all'indirizzo
\param{cpuset}, l'insieme dei processori sui quali deve essere eseguito il
processo identificato tramite il valore passato in \param{pid}. Come in
avviene nelle architetture NUMA).
Infine se un gruppo di processi accede alle stesse risorse condivise (ad
-esempio una applicazione con più thread) può avere senso usare lo stesso
-processore in modo da sfruttare meglio l'uso della sua cache; questo
-ovviamente riduce i benefici di un sistema multiprocessore nell'esecuzione
-contemporanea dei thread, ma in certi casi (quando i thread sono inerentemente
+esempio una applicazione con più \itindex{thread} \textit{thread}) può avere
+senso usare lo stesso processore in modo da sfruttare meglio l'uso della sua
+cache; questo ovviamente riduce i benefici di un sistema multiprocessore
+nell'esecuzione contemporanea dei \itindex{thread} \textit{thread}, ma in
+certi casi (quando i \itindex{thread} \textit{thread} sono inerentemente
serializzati nell'accesso ad una risorsa) possono esserci sufficienti vantaggi
nell'evitare la perdita della cache da rendere conveniente l'uso dell'affinità
di processore.
valore per un processo specifico usando la funzione
\funcd{sched\_getaffinity}, il suo prototipo è:
\begin{prototype}{sched.h}
- {int sched\_getaffinity (pid\_t pid, const cpu\_set\_t *cpuset)}
+ {int sched\_getaffinity (pid\_t pid, unsigned int cpusetsize,
+ const cpu\_set\_t *cpuset)}
Legge la maschera di affinità del processo \param{pid}.
\bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
sono compiute nello stesso spazio di indirizzi del processo. Per questo, anche
il solo accesso o l'assegnazione di una variabile possono non essere più
operazioni atomiche (torneremo su questi aspetti in
-sez.~\ref{sec:sig_control}).
+sez.~\ref{sec:sig_adv_control}).
In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t},
il cui accesso è assicurato essere atomico. In pratica comunque si può
\subsection{Le funzioni rientranti}
\label{sec:proc_reentrant}
+\index{funzioni!rientranti|(}
+
Si dice \textsl{rientrante} una funzione che può essere interrotta in
qualunque punto della sua esecuzione ed essere chiamata una seconda volta da
-un altro thread di esecuzione senza che questo comporti nessun problema
-nell'esecuzione della stessa. La problematica è comune nella programmazione
-multi-thread, ma si hanno gli stessi problemi quando si vogliono chiamare
-delle funzioni all'interno dei gestori dei segnali.
+un altro \itindex{thread} \textit{thread} di esecuzione senza che questo
+comporti nessun problema nell'esecuzione della stessa. La problematica è
+comune nella programmazione \itindex{thread} \textit{multi-thread}, ma si
+hanno gli stessi problemi quando si vogliono chiamare delle funzioni
+all'interno dei gestori dei segnali.
Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
-queste infatti vengono allocate nello \itindex{stack} stack, ed un'altra
-invocazione non fa altro che allocarne un'altra copia. Una funzione può non
-essere rientrante quando opera su memoria che non è nello \itindex{stack}
-stack. Ad esempio una funzione non è mai rientrante se usa una variabile
-globale o statica.
+queste infatti vengono allocate nello \itindex{stack} \textit{stack}, ed
+un'altra invocazione non fa altro che allocarne un'altra copia. Una funzione
+può non essere rientrante quando opera su memoria che non è nello
+\itindex{stack} \textit{stack}. Ad esempio una funzione non è mai rientrante
+se usa una variabile globale o statica.
Nel caso invece la funzione operi su un oggetto allocato dinamicamente, la
cosa viene a dipendere da come avvengono le operazioni: se l'oggetto è creato
In genere le funzioni di libreria non sono rientranti, molte di esse ad
esempio utilizzano variabili statiche, le \acr{glibc} però mettono a
-disposizione due macro di compilatore, \macro{\_REENTRANT} e
+disposizione due macro di compilatore,\footnote{si ricordi quanto illustrato
+ in sez.~\ref{sec:intro_gcc_glibc_std}.} \macro{\_REENTRANT} e
\macro{\_THREAD\_SAFE}, la cui definizione attiva le versioni rientranti di
varie funzioni di libreria, che sono identificate aggiungendo il suffisso
\code{\_r} al nome della versione normale.
+\index{funzioni!rientranti|)}
+
+
% LocalWords: multitasking like VMS child process identifier pid sez shell fig
% LocalWords: parent kernel init pstree keventd kswapd table struct linux call
% LocalWords: nell'header scheduler system interrupt timer HZ asm Hertz clock
% LocalWords: l'alpha tick fork wait waitpid exit exec image glibc int pgid ps
-% LocalWords: sid threads thread Ingo Molnar ppid getpid getppid sys unistd LD
+% LocalWords: sid thread Ingo Molnar ppid getpid getppid sys unistd LD
% LocalWords: void ForkTest tempnam pathname sibling cap errno EAGAIN ENOMEM
% LocalWords: stack read only copy write tab client spawn forktest sleep PATH
% LocalWords: source LIBRARY scheduling race condition printf descriptor dup
% LocalWords: shmctl ioperm iopl chroot ptrace accounting swap reboot hangup
% LocalWords: vhangup mknod lease permitted inherited inheritable bounding AND
% LocalWords: capability capget capset header ESRCH undef version obj clear PT
-% LocalWords: pag ssize length proc capgetp prehemptive cache runnable Stopped
+% LocalWords: pag ssize length proc capgetp preemptive cache runnable Stopped
% LocalWords: Uninterrutible SIGSTOP soft slice nice niceness counter which SC
% LocalWords: getpriority who setpriority RTLinux RTAI Adeos fault FIFO First
% LocalWords: yield Robin setscheduler policy param OTHER priority setparam to
% LocalWords: cpusetsize cpuset atomic tickless redirezione WCONTINUED stopped
% LocalWords: waitid NOCLDSTOP ENOCHLD WIFCONTINUED ifdef endif idtype siginfo
% LocalWords: infop ALL WEXITED WSTOPPED WNOWAIT signo CLD EXITED KILLED page
-% LocalWords: CONTINUED
+% LocalWords: CONTINUED sources forking Spawned successfully executing exiting
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
+% LocalWords: next cat for COMMAND pts bash defunct