% TODO la task_struct è cambiata per qualche dettaglio vedi anche
% http://www.ibm.com/developerworks/linux/library/l-linux-process-management/
+% TODO completare la parte su quando viene chiamato lo scheduler.
Come accennato in sez.~\ref{sec:intro_unix_struct} è lo \itindex{scheduler}
\textit{scheduler} che decide quale processo mettere in esecuzione; esso viene
eseguito ad ogni system call ed ad ogni interrupt,\footnote{più in una serie
- di altre occasioni.}
-% TODO completare questa parte su quando viene chiamato lo scheduler.
-(ma può essere anche attivato esplicitamente). Il timer di sistema provvede
-comunque a che esso sia invocato periodicamente; generando un interrupt
-periodico secondo la frequenza specificata dalla costante
-\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
- \itindex{clock~tick} \textit{clock tick} (vedi
+ di altre occasioni.} ma può essere anche attivato esplicitamente. Il timer
+di sistema provvede comunque a che esso sia invocato periodicamente; generando
+un interrupt periodico secondo la frequenza specificata dalla costante
+\const{HZ},\footnote{fino al kernel 2.4 il valore di \const{HZ} era 100 su
+ tutte le architetture tranne l'alpha, per cui era 1000, nel 2.6 è stato
+ portato a 1000 su tutte; dal 2.6.13 lo si può impostare in fase di
+ compilazione del kernel, con un default di 250 e valori possibili di 100,
+ 250, 1000 e dal 2.6.20 anche 300 (che è divisibile per le frequenze di
+ refresh della televisione); occorre fare 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,
da parte del processore che può essere messo in stato di sospensione anche
per lunghi periodi di tempo.}
-
Ogni volta che viene eseguito, lo \itindex{scheduler} \textit{scheduler}
effettua il calcolo delle priorità dei vari processi attivi (torneremo su
questo in sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba
\subsection{Una panoramica sulle funzioni fondamentali}
\label{sec:proc_handling_intro}
-In un sistema unix-like i processi vengono sempre creati da altri processi
-tramite la funzione \func{fork}; il nuovo processo (che viene chiamato
-\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo
-processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene
-eseguito in maniera indipendente (le differenze fra padre e figlio sono
+Tradizionalmente in un sistema unix-like i processi vengono sempre creati da
+altri processi tramite la funzione \func{fork}; il nuovo processo (che viene
+chiamato \textsl{figlio}) creato dalla \func{fork} è una copia identica del
+processo processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e
+viene eseguito in maniera indipendente (le differenze fra padre e figlio sono
affrontate in dettaglio in sez.~\ref{sec:proc_fork}).
Se si vuole che il processo padre si fermi fino alla conclusione del processo
\label{sec:proc_fork}
La funzione \funcd{fork} è la funzione fondamentale della gestione dei
-processi: come si è detto l'unico modo di creare un nuovo processo è
-attraverso l'uso di questa funzione, essa quindi riveste un ruolo centrale
-tutte le volte che si devono scrivere programmi che usano il multitasking. Il
-prototipo della funzione è:
+processi: come si è detto tradizionalmente l'unico modo di creare un nuovo
+processo era attraverso l'uso di questa funzione,\footnote{in realtà oggi la
+ system call usata più comunemente da Linux per creare nuovi processi è
+ \func{clone} (vedi \ref{sec:process_clone}) , anche perché a partire dalle
+ \acr{glibc} 2.3.3 non viene più usata la system call originale, ma la stessa
+ \func{fork} viene implementata tramite \func{clone}, cosa che consente una
+ migliore interazione coi \textit{thread}.} essa quindi riveste un ruolo
+centrale tutte le volte che si devono scrivere programmi che usano il
+multitasking.\footnote{oggi questa rilevanza, con la diffusione dell'uso dei
+ \textit{thread} che tratteremo al cap.~\ref{cha:threads}, è in parte minore,
+ ma \func{fork} resta comunque la funzione principale per la creazione di
+ processi.} Il prototipo della funzione è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{unistd.h}
con il nostro esempio, le varie scritture risulteranno mescolate fra loro in
una sequenza impredicibile. Per questo le modalità con cui in genere si usano
i file dopo una \func{fork} sono sostanzialmente due:
-\begin{enumerate}
+\begin{enumerate*}
\item Il processo padre aspetta la conclusione del figlio. In questo caso non
è necessaria nessuna azione riguardo ai file, in quanto la sincronizzazione
della posizione corrente dopo eventuali operazioni di lettura e scrittura
\item L'esecuzione di padre e figlio procede indipendentemente. In questo caso
ciascuno dei due processi deve chiudere i file che non gli servono una volta
che la \func{fork} è stata eseguita, per evitare ogni forma di interferenza.
-\end{enumerate}
+\end{enumerate*}
Oltre ai file aperti i processi figli ereditano dal padre una serie di altre
proprietà; la lista dettagliata delle proprietà che padre e figlio hanno in
ed il terminale di controllo (vedi sez.~\ref{sec:sess_proc_group});
\item la directory di lavoro e la directory radice (vedi
sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot});
-\item la maschera dei permessi di creazione (vedi
+\item la maschera dei permessi di creazione dei file (vedi
sez.~\ref{sec:file_perm_management});
\item la maschera dei segnali bloccati (vedi sez.~\ref{sec:sig_sigmask}) e le
azioni installate (vedi sez.~\ref{sec:sig_gen_beha});
\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit});
\item il valori di \textit{nice}, le priorità real-time e le affinità di
processore (vedi sez.~\ref{sec:proc_sched_stand},
- sez.~\ref{sec:proc_real_time} e sez.\ref{sec:proc_sched_multiprocess});
+ sez.~\ref{sec:proc_real_time} e sez.~\ref{sec:proc_sched_multiprocess});
\item le variabili di ambiente (vedi sez.~\ref{sec:proc_environ}).
\end{itemize*}
-Le differenze fra padre e figlio dopo la \func{fork} invece sono:
+Le differenze fra padre e figlio dopo la \func{fork} invece sono:\footnote{a
+ parte le ultime quattro, relative a funzionalità specifiche di Linux, le
+ altre sono esplicitamente menzionate dallo standard POSIX.1-2001.}
\begin{itemize*}
\item il valore di ritorno di \func{fork};
-\item il \acr{pid} (\textit{process id});
+\item il \acr{pid} (\textit{process id}), assegnato ad un nuovo valore univoco;
\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
impostato al \acr{pid} del padre;
-\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
- sez.~\ref{sec:sys_cpu_times}) che nel figlio sono posti a zero;
-\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}), che non
- vengono ereditati dal figlio;
-\item gli allarmi ed i segnali pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che
- per il figlio vengono cancellati.
+\item i valori dei tempi di esecuzione (vedi sez.~\ref{sec:sys_cpu_times}) e
+ delle risorse usate (vedi sez.~\ref{sec:sys_resource_use}), che nel figlio
+ sono posti a zero;
+\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}) e sulla
+ memoria (vedi sez.~\ref{sec:proc_mem_lock}), che non vengono ereditati dal
+ figlio;
+\item gli allarmi (vedi sez.~\ref{sec:sig_alarm_abort}) ed i segnali pendenti
+ (vedi sez.~\ref{sec:sig_gen_beha}), che per il figlio vengono cancellati.
+\item le operazioni di I/O asincrono in corso (vedi
+ sez.~\ref{sec:file_asyncronous_io}) che non vengono ereditate dal figlio;
+\item gli aggiustamenti fatti dal padre ai semafori con \func{semop} (vedi
+ sez.~\ref{sec:ipc_sysv_sem}).
+\item le notifiche sui cambiamenti delle directory con \textit{dnotify} (vedi
+ sez.~\ref{sec:sig_notification}), che non vengono ereditate dal figlio;
+\item le mappature di memoria marcate come \const{MADV\_DONTFORK} (vedi
+ sez.~\ref{sec:file_memory_map}) che non vengono ereditate dal figlio;
+\item l'impostazione con \func{prctl} (vedi sez.~\ref{sec:prctl_xxx}) che
+ notifica al figlio la terminazione del padre viene cancellata;
+\item il segnale di terminazione del figlio è sempre \const{SIGCHLD} anche
+ qualora nel padre fosse stato modificato (vedi sez.~\ref{sec:process_clone}).
\end{itemize*}
-
Una seconda funzione storica usata per la creazione di un nuovo processo è
\func{vfork}, che è esattamente identica a \func{fork} ed ha la stessa
semantica e gli stessi errori; la sola differenza è che non viene creata la
Dato che Linux supporta il \itindex{copy~on~write} \textit{copy on write} la
perdita di prestazioni è assolutamente trascurabile, e l'uso di questa
-funzione (che resta un caso speciale della system call \func{\_\_clone}) è
-deprecato; per questo eviteremo di trattarla ulteriormente.
+funzione, che resta un caso speciale della system call \func{clone} (che
+tratteremo in dettaglio in sez.~\ref{sec:process_clone}) è deprecato; per
+questo eviteremo di trattarla ulteriormente.
\subsection{La conclusione di un processo}
comunque una serie di operazioni: chiude tutti i file aperti, rilascia la
memoria che stava usando, e così via; l'elenco completo delle operazioni
eseguite alla chiusura di un processo è il seguente:
-\begin{itemize}
+\begin{itemize*}
\item tutti i file descriptor sono chiusi;
\item viene memorizzato lo stato di terminazione del processo;
\item ad ogni processo figlio viene assegnato un nuovo padre (in genere
group} ciascun membro del gruppo viene bloccato, e poi gli vengono
inviati in successione i segnali \const{SIGHUP} e \const{SIGCONT}
(vedi ancora sez.~\ref{sec:sess_ctrl_term}).
-\end{itemize}
+\end{itemize*}
Oltre queste operazioni è però necessario poter disporre di un meccanismo
ulteriore che consenta di sapere come la terminazione è avvenuta: dato che in
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
Il comportamento di \func{waitpid} può inoltre essere modificato passando alla
funzione delle opportune opzioni tramite l'argomento \param{options}; questo
-deve essere specificato come maschera binaria dei flag riportati in
-tab.~\ref{tab:proc_waitpid_options},\footnote{oltre a queste in Linux sono
- previste del altre opzioni non standard, relative al comportamento con i
- \itindex{thread} \textit{thread}, che riprenderemo in
- sez.~\ref{sec:thread_xxx}.} che possono essere combinati fra loro con un OR
-aritmetico.
-
-L'uso dell'opzione \const{WNOHANG} consente di prevenire il blocco della
-funzione qualora nessun figlio sia uscito (o non si siano verificate le altre
-condizioni per l'uscita della funzione); in tal caso la funzione ritornerà un
-valore nullo anziché positivo.\footnote{anche in questo caso un valore
- positivo indicherà il \acr{pid} del processo di cui si è ricevuto lo stato
- ed un valore negativo un errore.}
+deve essere specificato come maschera binaria dei flag riportati nella prima
+parte in tab.~\ref{tab:proc_waitpid_options} che possono essere combinati fra
+loro con un OR aritmetico. Nella seconda parte della stessa tabella si sono
+riportati anche alcuni valori non standard specifici di Linux, che consentono
+un controllo più dettagliato per i processi creati con la system call generica
+\func{clone} (vedi sez.~\ref{sec:process_clone}) usati principalmente per la
+gestione della terminazione dei \itindex{thread} \textit{thread} (vedi
+sez.~\ref{sec:thread_xxx}).
\begin{table}[!htb]
\centering
\const{WCONTINUED}& Ritorna anche quando un processo figlio che era stato
fermato ha ripreso l'esecuzione.\footnotemark \\
\hline
+ \const{\_\_WCLONE}& Attende solo per i figli creati con \func{clone},
+ vale a dire processi che non emettono nessun segnale
+ o emettono un segnale diverso da \const{SIGCHL} alla
+ terminazione. \\
+ \const{\_\_WALL} & Attende per qualunque processo figlio. \\
+ \const{\_\_WNOTHREAD}& Non attende per i figli di altri \textit{thread}
+ dello stesso gruppo. \\
+ \hline
\end{tabular}
\caption{Costanti che identificano i bit dell'argomento \param{options}
della funzione \func{waitpid}.}
\footnotetext{disponibile solo a partire dal kernel 2.6.10.}
+L'uso dell'opzione \const{WNOHANG} consente di prevenire il blocco della
+funzione qualora nessun figlio sia uscito (o non si siano verificate le altre
+condizioni per l'uscita della funzione); in tal caso la funzione ritornerà un
+valore nullo anziché positivo.\footnote{anche in questo caso un valore
+ positivo indicherà il \acr{pid} del processo di cui si è ricevuto lo stato
+ ed un valore negativo un errore.}
+
Le altre due opzioni \const{WUNTRACED} e \const{WCONTINUED} consentono
rispettivamente di tracciare non la terminazione di un processo, ma il fatto
che esso sia stato fermato, o fatto ripartire, e sono utilizzate per la
attendono la terminazione di un processo figlio e ritornano il relativo
\acr{pid} e lo stato di terminazione nell'argomento \param{status}.
-In generale in un programma non si vuole essere forzati ad attendere la
-conclusione di un processo figlio per proseguire l'esecuzione, specie se tutto
-questo serve solo per leggerne lo stato di chiusura (ed evitare eventualmente
-la presenza di \index{zombie} \textit{zombie}). Per questo la modalità più
-comune di chiamare queste funzioni è quella di utilizzarle all'interno di un
-\textit{signal handler} (vedremo un esempio di come gestire \const{SIGCHLD}
-con i segnali in sez.~\ref{sec:sig_example}). In questo caso infatti, dato che
-il segnale è generato dalla terminazione di un figlio, avremo la certezza che
-la chiamata a \func{waitpid} non si bloccherà.
-
-Come accennato sia \func{wait} che \func{waitpid} restituiscono lo stato di
-terminazione del processo tramite il puntatore \param{status} (se non
-interessa memorizzare lo stato si può passare un puntatore nullo). Il valore
-restituito da entrambe le funzioni dipende dall'implementazione, ma
-tradizionalmente alcuni bit (in genere 8) sono riservati per memorizzare lo
-stato di uscita, e altri per indicare il segnale che ha causato la
-terminazione (in caso di conclusione anomala), uno per indicare se è stato
-generato un \itindex{core~dump} \textit{core dump}, ecc.\footnote{le
- definizioni esatte si possono trovare in \file{<bits/waitstatus.h>} ma
- questo file non deve mai essere usato direttamente, esso viene incluso
- attraverso \file{<sys/wait.h>}.}
-
-Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
-analizzare lo stato di uscita. Esse sono definite sempre in
-\file{<sys/wait.h>} ed elencate in tab.~\ref{tab:proc_status_macro} (si tenga
-presente che queste macro prendono come parametro la variabile di tipo
-\ctyp{int} puntata da \param{status}).
-
\begin{table}[!htb]
\centering
\footnotesize
\label{tab:proc_status_macro}
\end{table}
-\footnotetext[18]{questa macro non è definita dallo standard POSIX.1-2001, ma è
+\footnotetext[20]{questa macro non è definita dallo standard POSIX.1-2001, ma è
presente come estensione sia in Linux che in altri Unix, deve essere
pertanto utilizzata con attenzione (ad esempio è il caso di usarla in un
blocco \texttt{\#ifdef WCOREDUMP ... \#endif}.}
\footnotetext{è presente solo a partire dal kernel 2.6.10.}
+In generale in un programma non si vuole essere forzati ad attendere la
+conclusione di un processo figlio per proseguire l'esecuzione, specie se tutto
+questo serve solo per leggerne lo stato di chiusura (ed evitare eventualmente
+la presenza di \index{zombie} \textit{zombie}).
+
+Per questo la modalità più comune di chiamare queste funzioni è quella di
+utilizzarle all'interno di un \textit{signal handler} (vedremo un esempio di
+come gestire \const{SIGCHLD} con i segnali in sez.~\ref{sec:sig_example}). In
+questo caso infatti, dato che il segnale è generato dalla terminazione di un
+figlio, avremo la certezza che la chiamata a \func{waitpid} non si bloccherà.
+
+Come accennato sia \func{wait} che \func{waitpid} restituiscono lo stato di
+terminazione del processo tramite il puntatore \param{status} (se non
+interessa memorizzare lo stato si può passare un puntatore nullo). Il valore
+restituito da entrambe le funzioni dipende dall'implementazione, ma
+tradizionalmente alcuni bit (in genere 8) sono riservati per memorizzare lo
+stato di uscita, e altri per indicare il segnale che ha causato la
+terminazione (in caso di conclusione anomala), uno per indicare se è stato
+generato un \itindex{core~dump} \textit{core dump}, ecc.\footnote{le
+ definizioni esatte si possono trovare in \file{<bits/waitstatus.h>} ma
+ questo file non deve mai essere usato direttamente, esso viene incluso
+ attraverso \file{<sys/wait.h>}.}
+
+Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
+analizzare lo stato di uscita. Esse sono definite sempre in
+\file{<sys/wait.h>} ed elencate in tab.~\ref{tab:proc_status_macro}; si tenga
+presente che queste macro prevedono che gli si passi come parametro la
+variabile di tipo \ctyp{int} puntata dall'argomento \param{status} restituito
+da \func{wait} o \func{waitpid}.
+
Si tenga conto che nel caso di conclusione anomala il valore restituito da
-\val{WTERMSIG} può essere confrontato con le costanti definite in
-\file{signal.h} ed elencate in tab.~\ref{tab:sig_signal_list}, e stampato
-usando le apposite funzioni trattate in sez.~\ref{sec:sig_strsignal}.
+\val{WTERMSIG} può essere confrontato con le costanti che identificano i
+segnali definite in \file{signal.h} ed elencate in
+tab.~\ref{tab:sig_signal_list}, e stampato usando le apposite funzioni
+trattate in sez.~\ref{sec:sig_strsignal}.
A partire dal kernel 2.6.9, sempre in conformità allo standard POSIX.1-2001, è
stata introdotta una nuova funzione di attesa che consente di avere un
\end{functions}
La funzione prevede che si specifichi quali processi si intendono osservare
-usando i due argomenti \param{idtype} ed \param{id}; il primo indica se si
-vuole porsi in attesa su un singolo processo, un gruppo di processi o un
+usando i due argomenti \param{idtype} ed \param{id}; il primo indica se ci si
+vuole porre in attesa su un singolo processo, un gruppo di processi o un
processo qualsiasi, e deve essere specificato secondo uno dei valori di
tab.~\ref{tab:proc_waitid_idtype}; il secondo indica, a seconda del valore del
primo, quale processo o quale gruppo di processi selezionare.
-
\begin{table}[!htb]
\centering
\footnotesize
\begin{figure}[htb]
\centering
- \includegraphics[width=15cm]{img/exec_rel}
+ \includegraphics[width=12cm]{img/exec_rel}
\caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.}
\label{fig:proc_exec_relat}
\end{figure}
l'ambiente.
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}
+\func{exec} mantiene la gran parte delle proprietà del processo chiamante; una
+lista delle più significative è la seguente:
+\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 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
- sez.~\ref{sec:sig_sigmask});
\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}
-
-Inoltre i segnali che sono stati impostati per essere ignorati nel processo
-chiamante mantengono la stessa impostazione pure nel nuovo programma, tutti
-gli altri segnali vengono impostati alla loro azione predefinita. Un caso
-speciale è il segnale \const{SIGCHLD} che, quando impostato a
-\const{SIG\_IGN}, può anche non essere reimpostato a \const{SIG\_DFL} (si veda
-sez.~\ref{sec:sig_gen_beha}).
-
-La gestione dei file aperti dipende dal valore che ha il flag di
-\itindex{close-on-exec} \textit{close-on-exec} (vedi anche
-sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è
-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.
-
-Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale}
-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}).
+\item i valori delle variabili \var{tms\_utime}, \var{tms\_stime};
+ \var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times});
+% TODO ===========Importante=============
+% TODO questo sotto è incerto, verificare
+% TODO ===========Importante=============
+\item la maschera dei segnali (si veda sez.~\ref{sec:sig_sigmask}).
+\end{itemize*}
+
+Una serie di proprietà del processo originale, che non avrebbe senso mantenere
+in un programma che esegue un codice completamente diverso in uno spazio di
+indirizzi totalmente indipendente e ricreato da zero, vengono perse con
+l'esecuzione di \func{exec}; lo standard POSIX.1-2001 prevede che le seguenti
+proprietà non vengano preservate:
+\begin{itemize*}
+\item l'insieme dei segnali pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che
+ viene cancellato;
+\item gli eventuali stack alternativi per i segnali (vedi
+ sez.~\ref{sec:sig_specific_features});
+\item i \textit{directory stream} (vedi sez.~\ref{sec:file_dir_read}), che
+ vengono chiusi;
+\item le mappature dei file in memoria (vedi sez.~\ref{sec:file_memory_map});
+\item i segmenti di memoria condivisa SysV (vedi sez.~\ref{sec:ipc_sysv_shm})
+ e POSIX (vedi sez.~\ref{sec:ipc_posix_shm});
+\item i blocchi sulla memoria (vedi sez.~\ref{sec:proc_mem_lock});
+\item le funzioni registrate all'uscita (vedi sez.~\ref{sec:proc_atexit});
+\item i semafori e le code di messaggi POSIX (vedi
+ sez.~\ref{sec:ipc_posix_sem} e sez.~\ref{sec:ipc_posix_mq});
+\item i timer POSIX (vedi sez.~\ref{sec:sig_timer_adv}).
+\end{itemize*}
+
+I segnali che sono stati impostati per essere ignorati nel processo chiamante
+mantengono la stessa impostazione pure nel nuovo programma, ma tutti gli altri
+segnali, ed in particolare quelli per i quali è stato installato un gestore
+vengono impostati alla loro azione predefinita (vedi
+sez.~\ref{sec:sig_gen_beha}). Un caso speciale è il segnale \const{SIGCHLD}
+che, quando impostato a \const{SIG\_IGN}, potrebbe anche essere reimpostato a
+\const{SIG\_DFL}, anche se questo con Linux non avviene.\footnote{lo standard
+ POSIX.1-2001 prevede che questo comportamento sia deciso dalla singola
+ implementazione, quella di Linux è di non modificare l'impostazione
+ precedente.}
+
+Oltre alle precedenti che sono completamente generali e disponibili anche su
+altri sistemi unix-like, esistono altre proprietà dei processi, attinenti
+caratteristiche specifiche di Linux, che non vengono preservate
+nell'esecuzione della funzione \func{exec}, queste sono:
+\begin{itemize*}
+\item le operazione di I/O asincrono (vedi sez.~\ref{sec:file_asyncronous_io})
+ pendenti vengono cancellate;
+\item le \itindex{capabilities} \textit{capabilities} vengono modificate come
+ illustrato in sez.~\ref{sec:proc_capabilities};
+\item tutti i \itindex{thread} \textit{thread} tranne il chiamante (vedi
+ sez.~\ref{sec:thread_xxx}) sono cancellati e tutti gli oggetti ad essi
+ relativi (vedi sez.~\ref{sec:thread_xxx}) rimossi;
+\item viene impostato il flag \const{PR\_SET\_DUMPABLE} di \func{prctl} (vedi
+ sez.~\ref{sec:prctl_xxx}) a meno che il programma da eseguire non sia
+ \itindex{suid~bit} \acr{suid} o \itindex{sgid~bit} \acr{sgid} (vedi
+ sez.~\ref{sec:proc_access_id});
+\item il flag \const{PR\_SET\_KEEPCAPS} di \func{prctl} (vedi
+ sez.~\ref{sec:prctl_xxx}) viene cancellato;
+\item il nome del processo viene impostato al nome del file contenente il
+ programma messo in esecuzione;
+\item il segnale di terminazione viene reimpostato a \const{SIGCHLD};
+\item l'ambiente viene reinizializzato impostando le variabili attinenti alla
+ localizzazione al valore di default POSIX.
+\end{itemize*}
+
+La gestione dei file aperti nel passaggio al nuovo programma lanciato con
+\func{exec} dipende dal valore che ha il flag di \itindex{close-on-exec}
+\textit{close-on-exec} (vedi anche sez.~\ref{sec:file_fcntl}) per ciascun file
+descriptor. I file per cui è 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.
+
+Il comportamento della funzione in relazione agli identificatori relativi al
+controllo di accesso verrà trattato in dettaglio in sez.~\ref{sec:proc_perms},
+qui è sufficiente anticipare (si faccia riferimento a
+sez.~\ref{sec:proc_access_id} per la definizione di questi identificatori)
+come l'\textsl{user-ID reale} ed il \textsl{group-ID reale} restano sempre gli
+stessi, mentre l'\textsl{user-ID salvato} ed il \textsl{group-ID salvato}
+vengono impostati rispettivamente all'\textsl{user-ID effettivo} ed il
+\textsl{group-ID effettivo}, questi ultimi normalmente non vengono modificati,
+a meno che il file di cui viene chiesta l'esecuzione non 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.
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
scrivere codice portabile.
-\section{La gestione della priorità di esecuzione}
+\section{La gestione della priorità dei processi}
\label{sec:proc_priority}
In questa sezione tratteremo più approfonditamente i meccanismi con il quale
lo \itindex{scheduler} \textit{scheduler} assegna la CPU ai vari processi
attivi. In particolare prenderemo in esame i vari meccanismi con cui viene
gestita l'assegnazione del tempo di CPU, ed illustreremo le varie funzioni di
-gestione.
+gestione. Tratteremo infine anche le altre priorità dei processi (come quelle
+per l'accesso a disco) divenute disponibili con i kernel più recenti.
-% TODO: rivedere alla luce degli aggiornamenti del 2.6 (man sched_setscheduler)
\subsection{I meccanismi di \textit{scheduling}}
\label{sec:proc_sched}
\begin{table}[htb]
\footnotesize
\centering
- \begin{tabular}[c]{|p{2.8cm}|c|p{10cm}|}
+ \begin{tabular}[c]{|p{2.4cm}|c|p{9cm}|}
\hline
\textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\
\hline
\hline
\textbf{Runnable}& \texttt{R} & Il processo è in esecuzione o è pronto ad
essere eseguito (cioè è in attesa che gli
- venga assegnata la CPU). \\
+ venga assegnata la CPU).\\
\textbf{Sleep} & \texttt{S} & Il processo è in attesa di un
risposta dal sistema, ma può essere
- interrotto da un segnale. \\
+ interrotto da un segnale.\\
\textbf{Uninterrutible Sleep}& \texttt{D} & Il processo è in
attesa di un risposta dal sistema (in
genere per I/O), e non può essere
- interrotto in nessuna circostanza. \\
+ interrotto in nessuna circostanza.\\
\textbf{Stopped} & \texttt{T} & Il processo è stato fermato con un
\const{SIGSTOP}, o è tracciato.\\
\textbf{Zombie}\index{zombie} & \texttt{Z} & Il processo è terminato ma il
2.6.25, sostanzialmente identico
all'\textbf{Uninterrutible Sleep} con la
sola differenza che il processo può
- terminato (con \const{SIGKILL}).\\
+ terminato con \const{SIGKILL} (usato per
+ lo più per NFS).\\
\hline
\end{tabular}
\caption{Elenco dei possibili stati di un processo in Linux, nella colonna
\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
da essere rimesso in coda alla lista dei processi con la stessa priorità per
permettere ad un altro di essere eseguito; se però il processo è l'unico ad
essere presente sulla coda l'esecuzione non sarà interrotta. In genere usano
-questa funzione i processi in modalità \textit{fifo}, per permettere
+questa funzione i processi con politica \const{SCHED\_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.
+La funzione può essere utilizzata anche con processi che usano lo scheduling
+ordinario, ma in questo caso il comportamento non è ben definito, e dipende
+dall'implementazione. Fino al kernel 2.6.23 questo comportava che i processi
+venissero messi in fondo alla coda di quelli attivi, con la possibilità di
+essere rimessi in esecuzione entro breve tempo, con l'introduzione del
+\textit{Completely Fair Scheduler} questo comportamento è cambiato ed un
+processo che chiama la funzione viene inserito nella lista dei processi
+inattivo, con un tempo molto maggiore.\footnote{è comunque possibile
+ ripristinare un comportamento analogo al precedente scrivendo il valore 1
+ nel file \texttt{/proc/sys/kernel/sched\_compat\_yield}.}
+
+
\subsection{Il controllo dello \textit{scheduler} per i sistemi
multiprocessore}
la cui risposta è critica) e si vuole la massima velocità, con questa
interfaccia diventa possibile selezionare gruppi di processori utilizzabili in
maniera esclusiva. Lo stesso dicasi quando l'accesso a certe risorse (memoria
-o periferiche) può avere un costo diverso a seconda del processore (come
-avviene nelle architetture NUMA).
+o periferiche) può avere un costo diverso a seconda del processore, come
+avviene nelle architetture NUMA (\textit{Non-Uniform Memory Access}).
Infine se un gruppo di processi accede alle stesse risorse condivise (ad
esempio una applicazione con più \itindex{thread} \textit{thread}) può avere
\itindend{CPU~affinity}
+\subsection{Le priorità per le operazioni di I/O}
+\label{sec:io_priority}
+
+A lungo l'unica priorità usata per i processi è stata quella relativa
+all'assegnazione dell'uso del processore. Ma il processore non è l'unica
+risorsa che i processi devono contendersi, un'altra, altrettanto importante
+per le prestazioni, è quella dell'accesso a disco. Per questo motivo sono
+stati introdotti diversi \textit{I/O scheduler} in grado di distribuire in
+maniera opportuna questa risorsa ai vari processi. Fino al kernel 2.6.17 era
+possibile soltanto differenziare le politiche generali di gestione, scegliendo
+di usare un diverso \textit{I/O scheduler}; a partire da questa versione, con
+l'introduzione dello scheduler CFQ (\textit{Completely Fair Queuing}) è
+divenuto possibile, qualora si usi questo scheduler, impostare anche delle
+diverse priorità di accesso per i singoli processi.\footnote{al momento
+ (kernel 2.6.31), le priorità di I/O sono disponibili soltanto per questo
+ scheduler.}
+
+La scelta dello scheduler di I/O si può fare in maniera generica a livello di
+avvio del kernel assegnando il nome dello stesso al parametro
+\texttt{elevator}, mentre se ne può indicare uno per l'accesso al singolo
+disco scrivendo nel file \texttt{/sys/block/\textit{dev}/queue/scheduler}
+(dove \texttt{\textit{dev}} è il nome del dispositivo associato al disco); gli
+scheduler disponibili sono mostrati dal contenuto dello stesso file che
+riporta fra parentesi quadre quello attivo, il default in tutti i kernel
+recenti è proprio il \texttt{cfq},\footnote{nome con cui si indica appunto lo
+ scheduler \textit{Completely Fair Queuing}.} che supporta le priorità. Per i
+dettagli sulle caratteristiche specifiche degli altri scheduler, la cui
+discussione attiene a problematiche di ambito sistemistico, si consulti la
+documentazione nella directory \texttt{Documentation/block/} dei sorgenti del
+kernel.
+
+Una volta che si sia impostato lo scheduler CFQ ci sono due specifiche system
+call, specifiche di Linux, che consentono di leggere ed impostare le priorità
+di I/O.\footnote{se usate in corrispondenza ad uno scheduler diverso il loro
+ utilizzo non avrà alcun effetto.} Dato che non esiste una interfaccia
+diretta nelle \acr{glibc} per queste due funzioni occorrerà invocarle tramite
+la funzione \func{syscall} (come illustrato in
+sez.~\ref{sec:intro_syscall}). Le due funzioni sono \funcd{ioprio\_get} ed
+\funcd{ioprio\_set}; i rispettivi prototipi sono:
+\begin{functions}
+ \headdecl{linux/ioprio.h}
+ \funcdecl{int ioprio\_get(int which, int who)}
+ \funcdecl{int ioprio\_set(int which, int who, int ioprio)}
+
+ Rileva o imposta la priorità di I/O di un processo.
+
+ \bodydesc{Le funzioni ritornano rispettivamente un intero positivo
+ (indicante la priorità) o 0 in caso di successo e $-1$ in caso di errore,
+ nel qual caso \var{errno} può assumere i valori:
+ \begin{errlist}
+ \item[\errcode{ESRCH}] non esiste il processo indicato.
+ \item[\errcode{EINVAL}] i valori di \param{which} e \param{who} non sono
+ validi.
+ \item[\errcode{EPERM}] non si hanno i privilegi per eseguire
+ l'impostazione (solo per \func{ioprio\_set}).
+ \end{errlist} }
+\end{functions}
+
+Le funzioni leggono o impostano la priorità di I/O sulla base dell'indicazione
+dei due argomenti \param{which} e \param{who} che hanno lo stesso significato
+già visto per gli omonimi argomenti di \func{getpriority} e
+\func{setpriority}. Anche in questo caso si deve specificare il valore
+di \param{which} tramite le opportune costanti riportate in
+tab.~\ref{tab:ioprio_args} che consentono di indicare un singolo processo, i
+processi di un \textit{process group} (tratteremo questo argomento in
+sez.~\ref{sec:sess_proc_group}) o tutti o processi di un utente.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|c|c|l|}
+ \hline
+ \param{which} & \param{who} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IPRIO\_WHO\_PROCESS} & \type{pid\_t} & processo\\
+ \const{IPRIO\_WHO\_PRGR} & \type{pid\_t} & \itindex{process~group}
+ \textit{process group}\\
+ \const{IPRIO\_WHO\_USER} & \type{uid\_t} & utente\\
+ \hline
+ \end{tabular}
+ \caption{Legenda del valore dell'argomento \param{which} e del tipo
+ dell'argomento \param{who} delle funzioni \func{ioprio\_get} e
+ \func{ioprio\_set} per le tre possibili scelte.}
+ \label{tab:ioprio_args}
+\end{table}
+
+In caso di successo \func{ioprio\_get} restituisce un intero positivo che
+esprime il valore della priorità di I/O, questo valore è una maschera binaria
+composta da due parti, una che esprime la \textsl{classe} di scheduling di I/O
+del processo, l'altra che esprime, quando la classe di scheduling lo prevede,
+la priorità del processo all'interno della classe stessa. Questo stesso
+formato viene utilizzato per indicare il valore della priorità da impostare
+con l'argomento \param{ioprio} di \func{ioprio\_set}.
+
+Per la gestione dei valori che esprimono le priorità di I/O sono state
+definite delle opportune macro di preprocessore, riportate in
+tab.~\ref{tab:IOsched_class_macro}. I valori delle priorità si ottengono o si
+impostano usando queste macro. Le prime due si usano con il valore restituito
+da \func{ioprio\_get} e per ottenere rispettivamente la classe di
+scheduling\footnote{restituita dalla macro con i valori di
+ tab.~\ref{tab:IOsched_class}.} e l'eventuale valore della priorità. La terza
+macro viene invece usata per creare un valore di priorità da usare come
+argomento di \func{ioprio\_set} per eseguire una impostazione.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Macro} & \textbf{Significato}\\
+ \hline
+ \hline
+ \macro{IOPRIO\_PRIO\_CLASS}\texttt{(\textit{value})}
+ & dato il valore di una priorità come
+ restituito da \func{ioprio\_get} estrae il
+ valore della classe.\\
+ \macro{IOPRIO\_PRIO\_DATA}\texttt{(\textit{value})}
+ & dato il valore di una priorità come
+ restituito da \func{ioprio\_get} estrae il
+ valore della priorità.\\
+ \macro{IOPRIO\_PRIO\_VALUE}\texttt{(\textit{class},\textit{prio})}
+ & dato un valore di priorità ed una classe
+ ottiene il valore numerico da passare a
+ \func{ioprio\_set}.\\
+ \hline
+ \end{tabular}
+ \caption{Le macro per la gestione dei valori numerici .}
+ \label{tab:IOsched_class_macro}
+\end{table}
+
+Le classi di scheduling previste dallo scheduler CFQ sono tre, e ricalcano tre
+diverse modalità di distribuzione delle risorse analoghe a quelle già adottate
+anche nel funzionamento dello scheduler del processore. Ciascuna di esse è
+identificata tramite una opportuna costante, secondo quanto riportato in
+tab.~\ref{tab:IOsched_class}.
+
+La classe di priorità più bassa è \const{IOPRIO\_CLASS\_IDLE}; i processi in
+questa classe riescono ad accedere a disco soltanto quando nessun altro
+processo richiede l'accesso. Occorre pertanto usarla con molta attenzione,
+perché un processo in questa classe può venire completamente bloccato quando
+ci sono altri processi in una qualunque delle altre due classi che stanno
+accedendo al disco. Quando si usa questa classe non ha senso indicare un
+valore di priorità, dato che in questo caso non esiste nessuna gerarchia e la
+priorità è identica, la minima possibile, per tutti i processi.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Classe} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IOPRIO\_CLASS\_RT} & Scheduling di I/O \textit{real time}.\\
+ \const{IOPRIO\_CLASS\_BE} & Scheduling di I/O ordinario.\\
+ \const{IOPRIO\_CLASS\_IDLE}& Scheduling di I/O di priorità minima.\\
+ \hline
+ \end{tabular}
+ \caption{Costanti che identificano le classi di scheduling di I/O.}
+ \label{tab:IOsched_class}
+\end{table}
+
+La seconda classe di priorità di I/O è \const{IOPRIO\_CLASS\_BE} (il nome sta
+per \textit{best-effort}) che è quella usata ordinariamente da tutti
+processi. In questo caso esistono priorità diverse che consentono di
+assegnazione di una maggiore banda passante nell'accesso a disco ad un
+processo rispetto agli altri, con meccanismo simile a quello dei valori di
+\textit{nice} in cui si evita che un processo a priorità più alta possa
+bloccare indefinitamente quelli a priorità più bassa. In questo caso però le
+diverse priorità sono soltanto otto, indicate da un valore numerico fra 0 e 7
+e come per \textit{nice} anche in questo caso un valore più basso indica una
+priorità maggiore.
+
+
+Infine la classe di priorità di I/O \textit{real-time}
+\const{IOPRIO\_CLASS\_RT} ricalca le omonime priorità di processore: un
+processo in questa classe ha sempre la precedenza nell'accesso a disco
+rispetto a tutti i processi delle altre classi e di un processo nella stessa
+classe ma con priorità inferiore, ed è pertanto in grado di bloccare
+completamente tutti gli altri. Anche in questo caso ci sono 8 priorità diverse
+con un valore numerico fra 0 e 7, con una priorità più elevata per valori più
+bassi.
+
+In generale nel funzionamento ordinario la priorità di I/O di un processo
+viene impostata in maniera automatica nella classe \const{IOPRIO\_CLASS\_BE}
+con un valore ottenuto a partire dal corrispondente valore di \textit{nice}
+tramite la formula: $\mathtt{\mathit{prio}}=(\mathtt{\mathit{nice}}+20)/5$. Un
+utente ordinario può modificare con \func{ioprio\_set} soltanto le priorità
+dei processi che gli appartengono,\footnote{per la modifica delle priorità di
+ altri processi occorrono privilegi amministrativi, ed in particolare la
+ capacità \const{CAP\_SYS\_NICE} (vedi sez.~\ref{sec:proc_capabilities}).}
+cioè quelli il cui user-ID reale corrisponde all'user-ID reale o effettivo del
+chiamante. Data la possibilità di ottenere un blocco totale dello stesso, solo
+l'amministratore\footnote{o un processo con la capacità
+ \const{CAP\_SYS\_ADMIN} (vedi sez.~\ref{sec:proc_capabilities}).} può
+impostare un processo ad una priorità di I/O nella classe
+\const{IOPRIO\_CLASS\_RT} o \const{IOPRIO\_CLASS\_IDLE}.
+
+
+%TODO trattare le funzionalità per il NUMA
+% vedi man numa e le pagine di manuale relative
+% vedere anche dove metterle...
\section{Problematiche di programmazione multitasking}
\label{sec:proc_multi_prog}
% LocalWords: infop ALL WEXITED WSTOPPED WNOWAIT signo CLD EXITED KILLED page
% LocalWords: CONTINUED sources forking Spawned successfully executing exiting
% LocalWords: next cat for COMMAND pts bash defunct TRAPPED DUMPED Killable PR
-% LocalWords: SIGKILL static RLIMIT preemption PREEMPT VOLUNTARY IDLE
-
+% LocalWords: SIGKILL static RLIMIT preemption PREEMPT VOLUNTARY IDLE RTPRIO
+% LocalWords: Completely Fair compat Uniform CFQ Queuing elevator dev cfq RT
+% LocalWords: Documentation block syscall ioprio IPRIO CLASS class best effort
+% LocalWords: refresh semop dnotify MADV DONTFORK prctl WCLONE SIGCHL WALL
+% LocalWords: WNOTHREAD DUMPABLE KEEPCAPS
+
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"