Correzione ai limiti, aggiustate referenze e iniziato le funzioni per
[gapil.git] / prochand.tex
index 9d07969bf4a0e95896fb46566f84e5dd35f8c636..98a07883b31341efba1a9245828d1c3ea730cd98 100644 (file)
@@ -113,7 +113,6 @@ organizzati in un albero di directory (si veda
 comando \cmd{pstree} che permette di visualizzare questa struttura, alla cui
 base c'è \cmd{init} che è progenitore di tutti gli altri processi.
 
-
 Il kernel mantiene una tabella dei processi attivi, la cosiddetta
 \textit{process table}; per ciascun processo viene mantenuta una voce nella
 tabella dei processi costituita da una struttura \type{task\_struct}, che
@@ -134,7 +133,8 @@ riprese), 
 
 Come accennato in \secref{sec:intro_unix_struct} è lo \textit{scheduler} che
 decide quale processo mettere in esecuzione; esso viene eseguito ad ogni
-system call ed ad ogni interrupt, (ma può essere anche attivato
+system call ed ad ogni interrupt,\footnote{più in una serie di altre
+  occasioni. NDT completare questa parte.} (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 \macro{HZ}, definita in \file{asm/param.h}. Il
@@ -211,7 +211,7 @@ Come accennato nell'introduzione, ogni processo viene identificato dal sistema
 da un numero identificativo unico, il \textit{process id} o \acr{pid};
 quest'ultimo è un tipo di dato standard, il \type{pid\_t} che in genere è un
 intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato è
-\type{int}).
+\ctyp{int}).
 
 Il \acr{pid} viene assegnato in forma progressiva ogni volta che un nuovo
 processo viene creato, fino ad un limite che, essendo il \acr{pid} un numero
@@ -606,11 +606,11 @@ comune dopo l'esecuzione di una \func{fork} 
 \item la directory di lavoro e la directory radice (vedi
   \secref{sec:file_work_dir} e \secref{sec:file_chroot}).
 \item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
-\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigpending}) e le
+\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}) e le
   azioni installate (vedi \secref{sec:sig_gen_beha}).
 \item i segmenti di memoria condivisa agganciati al processo (vedi
 \secref{sec:ipc_xxx}). 
-\item i limiti sulle risorse (vedi \secref{sec:sys_xxx}).
+\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}).
 \item le variabili di ambiente (vedi \secref{sec:proc_environ}).
 \end{itemize*}
 le differenze fra padre e figlio dopo la \func{fork} invece sono:
@@ -895,18 +895,18 @@ specchietto riportato in \ntab:
 \begin{table}[!htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|c|p{10cm}|}
+  \begin{tabular}[c]{|c|c|p{8cm}|}
     \hline
-    \textbf{Valore} & \textbf{Significato}\\
+    \textbf{Valore} & \textbf{Macro} &\textbf{Significato}\\
     \hline
     \hline
-    $<-1$& attende per un figlio il cui \textit{process group} è uguale al
+    $<-1$& -- & attende per un figlio il cui \textit{process group} è uguale al
     valore assoluto di \var{pid}. \\
-    $-1$ & attende per un figlio qualsiasi, usata in questa maniera è
-    equivalente a \func{wait}.\\ 
-    $0$  & attende per un figlio il cui \textit{process group} è uguale a
-    quello del processo chiamante. \\
-    $>0$ & attende per un figlio il cui \acr{pid} è uguale al
+    $-1$ & \macro{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
+    questa maniera è equivalente a \func{wait}.\\ 
+    $0$  & \macro{WAIT\_MYPGRP} & attende per un figlio il cui \textit{process
+    group} è uguale a quello del processo chiamante. \\
+    $>0$ & -- &attende per un figlio il cui \acr{pid} è uguale al
     valore di \var{pid}.\\
     \hline
   \end{tabular}
@@ -938,10 +938,10 @@ In genere in un programma non si vuole essere forzati ad attendere la
 conclusione di un processo per proseguire, specie se tutto questo serve solo
 per leggerne lo stato di chiusura (ed evitare la presenza di \textit{zombie}),
 per questo la modalità più usata per chiamare queste funzioni è quella di
-utilizzarle all'interno di un \textit{signal handler} (torneremo sui segnali e
-su come gestire \macro{SIGCHLD} in \secref{sec:sig_sigwait_xxx}). In questo
-caso infatti, dato che il segnale è generato dalla terminazione di un figlio,
-avremo la certezza che la chiamata a \func{wait} non si bloccherà.
+utilizzarle all'interno di un \textit{signal handler} (vedremo un esempio di
+come gestire \macro{SIGCHLD} con i segnali in \secref{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{wait} non si bloccherà.
 
 \begin{table}[!htb]
   \centering
@@ -996,7 +996,7 @@ 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 \tabref{tab:proc_status_macro} (si tenga
 presente che queste macro prendono come parametro la variabile di tipo
-\type{int} puntata da \var{status}).
+\ctyp{int} puntata da \var{status}).
 
 Si tenga conto che nel caso di conclusione anomala il valore restituito da
 \macro{WTERMSIG} può essere confrontato con le costanti definite in
@@ -1015,15 +1015,14 @@ sulle risorse usate dal processo terminato e dai vari figli.  I prototipi di
 queste funzioni, che diventano accessibili definendo la costante
 \macro{\_USE\_BSD}, sono:
 \begin{functions}
-  \headdecl{sys/times.h} 
-  \headdecl{sys/types.h} 
-  \headdecl{sys/wait.h}        
-  \headdecl{sys/resource.h}
+  \headdecl{sys/times.h} \headdecl{sys/types.h} \headdecl{sys/wait.h}
+  \headdecl{sys/resource.h} 
+  
   \funcdecl{pid\_t wait4(pid\_t pid, int * status, int options, struct rusage
-    * rusage)} 
-  È identica a \func{waitpid} sia per comportamento che per i
-  valori dei parametri, ma restituisce in \param{rusage} un sommario delle
-  risorse usate dal processo (per i dettagli vedi \secref{sec:sys_xxx})
+    * rusage)}   
+  È identica a \func{waitpid} sia per comportamento che per i valori dei
+  parametri, ma restituisce in \param{rusage} un sommario delle risorse usate
+  dal processo.
 
   \funcdecl{pid\_t wait3(int *status, int options, struct rusage *rusage)}
   Prima versione, equivalente a \code{wait4(-1, \&status, opt, rusage)} è
@@ -1031,16 +1030,9 @@ queste funzioni, che diventano accessibili definendo la costante
 \end{functions}
 \noindent 
 la struttura \type{rusage} è definita in \file{sys/resource.h}, e viene
-utilizzata anche dalla funzione \func{getrusage} (vedi \secref{sec:sys_xxx})
-per ottenere le risorse di sistema usate da un processo; la sua definizione è
-riportata in \figref{fig:sys_rusage_struct}.
-
-In genere includere esplicitamente \file{<sys/time.h>} non è più
-necessario, ma aumenta la portabilità, e serve in caso si debba accedere
-ai campi di \var{rusage} definiti come \type{struct timeval}. La
-struttura è ripresa da BSD 4.3, attualmente (con il kernel 2.4.x) i soli
-campi che sono mantenuti sono: \var{ru\_utime}, \var{ru\_stime},
-\var{ru\_minflt}, \var{ru\_majflt}, e \var{ru\_nswap}.
+utilizzata anche dalla funzione \func{getrusage} (vedi
+\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
+processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}.
 
 
 \subsection{Le funzioni \func{exec}}
@@ -1063,8 +1055,8 @@ famiglia di funzioni) che possono essere usate per questo compito, in realt
 {int execve(const char *filename, char *const argv[], char *const envp[])}
   Esegue il programma contenuto nel file \param{filename}.
   
-  \bodydesc{La funzione ritorna -1 solo in caso di errore, nel qual caso
-    caso la \var{errno} può assumere i valori:
+  \bodydesc{La funzione ritorna solo in caso di errore, restituendo -1; nel
+    qual caso \var{errno} può assumere i valori:
   \begin{errlist}
   \item[\macro{EACCES}] il file non è eseguibile, oppure il filesystem è
     montato in \cmd{noexec}, oppure non è un file normale o un interprete.
@@ -1216,10 +1208,10 @@ la lista completa 
   \secref{sec:file_umask}) ed i \textit{lock} sui file (vedi
   \secref{sec:file_locking}).
 \item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
-  \secref{sec:sig_sigpending}).
-\item i limiti sulle risorse (vedi \secref{sec:sys_limits}).
+  \secref{sec:sig_sigmask}).
+\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limits}).
 \item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
-  \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:xxx_xxx}).
+  \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:sys_xxx}).
 \end{itemize*}
 
 Inoltre i segnali che sono stati settati per essere ignorati nel processo
@@ -1348,7 +1340,7 @@ rispettivamente \textit{real} ed \textit{effective}.
     \hline
   \end{tabular}
   \caption{Identificatori di utente e gruppo associati a ciascun processo con
-    indicazione dei suffissi usate dalle varie funzioni di manipolazione.}
+    indicazione dei suffissi usati dalle varie funzioni di manipolazione.}
   \label{tab:proc_uid_gid}
 \end{table}
 
@@ -1424,11 +1416,11 @@ processo, come copie dell'\textit{effective user id} e dell'\textit{effective
 fossero utente e gruppo effettivi all'inizio dell'esecuzione di un nuovo
 programma.
 
-Il \textit{filesystem user id} e il \textit{filesystem group id} sono una
-estensione introdotta in Linux per rendere più sicuro l'uso di NFS (torneremo
-sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una replica dei
-corrispondenti \textit{effective id}, ai quali si sostituiscono per tutte le
-operazioni di verifica dei permessi relativi ai file (trattate in
+Il \textit{filesystem user id} e il \textit{filesystem group id} sono
+un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS
+(torneremo sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una
+replica dei corrispondenti \textit{effective id}, ai quali si sostituiscono
+per tutte le operazioni di verifica dei permessi relativi ai file (trattate in
 \secref{sec:file_perm_overview}).  Ogni cambiamento effettuato sugli
 \textit{effective id} viene automaticamente riportato su di essi, per cui in
 condizioni normali se ne può tranquillamente ignorare l'esistenza, in quanto
@@ -1588,9 +1580,10 @@ Lo stesso problema di propagazione dei privilegi ad eventuali processi figli
 si porrebbe per i \textit{saved id}: queste funzioni derivano da
 un'implementazione che non ne prevede la presenza, e quindi non è possibile
 usarle per correggere la situazione come nel caso precedente. Per questo
-motivo in Linux tutte le volte che vengono usate per modificare uno degli
-identificatori ad un valore diverso dal \textit{real id} precedente, il
-\textit{saved id} viene sempre settato al valore dell'\textit{effective id}.
+motivo in Linux tutte le volte che tali funzioni vengono usate per modificare
+uno degli identificatori ad un valore diverso dal \textit{real id} precedente,
+il \textit{saved id} viene sempre settato al valore dell'\textit{effective
+  id}.
 
 
 
@@ -1821,11 +1814,9 @@ quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag
 \label{sec:proc_priority}
 
 In questa sezione tratteremo più approfonditamente i meccanismi con il quale
-lo \textit{scheduler}\footnote{che è la parte del kernel che si occupa di
-  stabilire quale processo dovrà essere posto in esecuzione.} 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.
+lo \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.
 
 
 \subsection{I meccanismi di \textit{scheduling}}
@@ -1833,29 +1824,77 @@ varie funzioni di gestione.
 
 La scelta di un meccanismo che sia in grado di distribuire in maniera efficace
 il tempo di CPU per l'esecuzione dei processi è sempre una questione delicata,
-ed oggetto di numerose ricerche; in ogni caso essa dipende in maniera
-essenziale anche dal tipo di utilizzo che deve essere fatto del sistema.
+ed oggetto di numerose ricerche; in generale essa dipende in maniera
+essenziale anche dal tipo di utilizzo che deve essere fatto del sistema, per
+cui non esiste un meccanismo che sia valido per tutti gli usi.
+
+La caratteristica specifica di un sistema multitasking come Linux è quella del
+cosiddetto \textit{prehemptive multitasking}: questo significa che al
+contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative
+  multitasking}) non sono i singoli processi, ma il kernel stesso a decidere
+quando la CPU deve essere passata ad un altro processo. Come accennato in
+\secref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
+apposita del kernel, lo \textit{scheduler}, il cui scopo è quello di
+distribuire al meglio il tempo di CPU fra i vari processi.
 
 La cosa è resa ancora più complicata dal fatto che con le architetture
-multi-processore si introduce anche la problematica dovuta alla scelta di
-quale sia la CPU più opportuna da utilizzare.\footnote{nei processori moderni
-  la presenza di ampie cache può rendere poco efficiente trasferire
-  l'esecuzione di un processo da una CPU ad un'altra, per cui occorrono
-  meccanismi per determinare quale è la migliore scelta fra le diverse CPU.}
-Tutto questo comunque appartiene alle sottigliezze dell'implementazione del
-kernel, e dal punto di vista dei programmi che girano in user space, anche
-quando si hanno più processori (e dei processi che sono eseguiti davvero in
-contemporanea), si può pensare alle politiche di scheduling come concernenti
-la risorsa \textsl{tempo di esecuzione}, la cui assegnazione sarà governata
-dagli stessi meccanismi di scelta di priorità, solo che nel caso di più
-processori sarà a disposizione di più di un processo alla volta.
-
-Si tenga presente inoltre che l'utilizzo della CPU è soltanto una delle
-risorse (insieme alla memoria e all'accesso alle periferiche) che sono
-necessarie per l'esecuzione di un programma, e spesso non è neanche la più
-importante. Per questo non è affatto detto che dare ad un programma la massima
-priorità di esecuzione abbia risultati significativi in termini di
-prestazioni.
+multi-processore si deve anche scegliere quale sia la CPU più opportuna da
+utilizzare.\footnote{nei processori moderni la presenza di ampie cache può
+  rendere poco efficiente trasferire l'esecuzione di un processo da una CPU ad
+  un'altra, per cui effettuare la migliore scelta fra le diverse CPU non è
+  banale.}  Tutto questo comunque appartiene alle sottigliezze
+dell'implementazione del kernel; dal punto di vista dei programmi che girano
+in user space, anche quando si hanno più processori (e dei processi che sono
+eseguiti davvero in contemporanea), le politiche di scheduling riguardano
+semplicemente l'allocazione della risorsa \textsl{tempo di esecuzione}, la cui
+assegnazione sarà governata dai meccanismi di scelta delle priorità che
+restano gli stessi indipendentemente dal numero di processori.
+
+Si tenga conto poi che i processi non devono solo eseguire del codice: ad
+esempio molto spesso saranno impegnati in operazioni di I/O, o potranno
+venire bloccati da un comando dal terminale, o sospesi per un certo periodo di
+tempo.  In tutti questi casi la CPU diventa disponibile ed è compito dello
+kernel provvedere a mettere in esecuzione un altro processo.
+
+Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del
+processo, in Linux un processo può trovarsi in uno degli stati riportati in
+\tabref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
+\textit{runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque
+sia la sua priorità, un processo non potrà mai essere messo in esecuzione
+fintanto che esso si trova in uno qualunque degli altri stati.
+
+\begin{table}[htb]
+  \centering
+  \begin{tabular}[c]{|p{3cm}|c|p{8cm}|}
+    \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).   \\
+    \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
+    risposta dal sistema, ma può essere 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. \\
+    \textbf{Stopped} & \texttt{T} & Il processo è stato fermato con un
+    \macro{SIGSTOP}, o è tracciato.\\
+    \textbf{Zombie} & \texttt{Z} & Il processo è terminato ma il suo stato di
+    terminazione non è ancora stato letto dal padre. \\
+    \hline
+  \end{tabular}
+  \caption{Elenco dei possibili stati di un processo in Linux, nella colonna
+    \texttt{STAT} si è riportata la corrispondente lettera usata dal comando 
+    \cmd{ps} nell'omonimo campo.}
+  \label{tab:proc_proc_states}
+\end{table}
+
+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
+programmi dipendono in maniera molto più critica dall'I/O). Per questo motivo
+non è affatto detto che dare ad un programma la massima priorità di esecuzione
+abbia risultati significativi in termini di prestazioni.
 
 Il meccanismo tradizionale di scheduling di Unix (che tratteremo in
 \secref{sec:proc_sched_stand}) è sempre stato basato su delle \textsl{priorità
@@ -1882,25 +1921,20 @@ Il concetto di priorit
 l'esecuzione, vince sempre quello con la priorità assoluta più alta, anche
 quando l'altro è in esecuzione (grazie al \textit{prehemptive scheduling}).
 Ovviamente questo avviene solo per i processi che sono pronti per essere
-eseguiti (cioè nello stato \textit{runnable},\footnote{lo stato di un processo
-  è riportato nel campo \texttt{STAT} dell'output del comando \cmd{ps},
-  abbiamo già visto che lo stato di \textit{zombie} è indicato con \texttt{Z},
-  gli stati \textit{runnable}, \textit{sleep} e di I/O (\textit{uninteruttible
-    sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.})
-la priorità assoluta viene invece ignorata per quelli che sono bloccati su una
-richiesta di I/O o in stato di \textit{sleep}.  La priorità assoluta viene in
+eseguiti (cioè nello stato \textit{runnable}).  La priorità assoluta viene in
 genere indicata con un numero intero, ed un valore più alto comporta una
 priorità maggiore. Su questa politica di scheduling torneremo in
 \secref{sec:proc_real_time}.
 
 In generale quello che succede in tutti gli Unix moderni è che ai processi
 normali viene sempre data una priorità assoluta pari a zero, e la decisione di
-assegnazione della CPU è fatta solo in base ad una priorità dinamica che è
-calcolata indipendentemente. È tuttavia possibile assegnare anche una priorità
-assoluta nel qual caso un processo avrà la precedenza su tutti gli altri di
-priorità inferiore che saranno eseguiti solo quando quest'ultimo non avrà
+assegnazione della CPU è fatta solo con il meccanismo tradizionale della
+priorità dinamica. In Linux tuttavia è possibile assegnare anche una priorità
+assoluta, nel qual caso un processo avrà la precedenza su tutti gli altri di
+priorità inferiore, che saranno eseguiti solo quando quest'ultimo non avrà
 bisogno della CPU.
 
+
 \subsection{Il meccanismo di \textit{scheduling} standard}
 \label{sec:proc_sched_stand}
 
@@ -1917,25 +1951,377 @@ questo la priorit
 essere eseguito, e quando un processo potrà subentrare ad un altro
 nell'esecuzione.
 
+Il meccanismo usato da Linux è piuttosto semplice, ad ogni processo è
+assegnata una \textit{time-slice}, cioè in intervallo di tempo (letteralmente
+una fetta) per il quale esso deve essere eseguito. Il valore della
+\textit{time-slice} è controllato dalla cosiddetta \textit{nice} (o
+\textit{niceness}) del processo.  Essa è contenuta nel campo \var{nice} di
+\var{task\_struct}; tutti i processi vengono creati con lo stesso valore, ed
+essa specifica il valore della durata iniziale della \textit{time-slice} che
+viene assegnato ad un altro campo della struttura (\var{counter}) quando il
+processo viene eseguito per la prima volta e diminuito progressivamente ad
+ogni interruzione del timer.
+
+Quando lo scheduler viene eseguito scandisce la coda dei processi in stato
+\textit{runnable} associando, sulla base del valore di \var{counter}, un peso
+a ciascun processo in attesa di esecuzione,\footnote{il calcolo del peso in
+  realtà è un po' più complicato, ad esempio nei sistemi multiprocessore viene
+  favorito un processo che è eseguito sulla stessa CPU, e a parità del valore
+  di \var{counter} viene favorito chi ha una priorità più elevata.} chi ha il
+peso più alto verrà posto in esecuzione, ed il precedente processo sarà
+spostato in fondo alla coda.  Dato che ad ogni interruzione del timer il
+valore di \var{counter} del processo corrente viene diminuito, questo assicura
+che anche i processi con priorità più bassa verranno messi in esecuzione.
+
+La priorità di un processo è così controllata attraverso il valore di
+\var{nice}, che stabilisce la durata della \textit{time-slice}; per il
+meccanismo appena descritto infatti un valore più lungo infatti assicura una
+maggiore attribuzione di CPU.  L'origine del nome di questo parametro sta nel
+fatto che in genere esso viene generalmente usato per diminuire la priorità di
+un processo, come misura di cortesia nei confronti degli altri.
+
+I processi infatti vengono creati dal sistema con lo stesso valore di
+\var{nice} (nullo) e nessuno è privilegiato rispetto agli altri; il valore può
+essere modificato solo attraverso la funzione \func{nice}, il cui prototipo è:
+\begin{prototype}{unistd.h}
+{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:
+  \begin{errlist}
+  \item[\macro{EPERM}] un processo senza i privilegi di amministratore ha
+    specificato un valore di \param{inc} negativo.
+  \end{errlist}}
+\end{prototype}
+
+L'argomento \param{inc} indica l'incremento del valore di \var{nice}:
+quest'ultimo può assumere valori compresi fra \macro{PRIO\_MIN} e
+\macro{PRIO\_MAX} (che nel caso di Linux sono $-19$ e $20$), ma per
+\param{inc} si può specificare un valore qualunque, positivo o negativo, ed il
+sistema provvederà a troncare il risultato nell'intervallo consentito. Valori
+positivi comportano maggiore \textit{cortesia} e cioè una diminuzione della
+priorità, ogni utente può solo innalzare il valore di un suo processo. Solo
+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 \func{getpriority}, derivata da BSD, il cui prototipo è:
+\begin{prototype}{sys/resource.h}
+{int getpriority(int which, int who)}
+  
+Restituisce il valore di \var{nice} per l'insieme dei processi specificati.
+
+  \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} può assumere i valori:
+  \begin{errlist}
+  \item[\macro{ESRCH}] non c'è nessun processo che corrisponda ai valori di
+  \param{which} e \param{who}.
+  \item[\macro{EINVAL}] il valore di \param{which} non è valido.
+  \end{errlist}}
+\end{prototype}
+\noindent (in vecchie versioni può essere necessario includere anche
+\file{<sys/time.h>}, questo non è più necessario con versioni recenti delle
+librerie, ma è comunque utile per portabilità).
+
+La funzione permette di leggere la priorità di un processo, di un gruppo di
+processi (vedi \secref{sec:sess_proc_group}) o di un utente, a seconda del
+valore di \param{which}, secondo la legenda di \tabref{tab:proc_getpriority},
+specificando un corrispondente valore per \param{who}; un valore nullo di
+quest'ultimo indica il processo, il gruppo di processi o l'utente correnti.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|c|c|l|}
+    \hline
+    \param{which} & \param{who} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{PRIO\_PROCESS} & \type{pid\_t} &  processo  \\
+    \macro{PRIO\_PRGR}    & \type{pid\_t} &  process group  \\
+    \macro{PRIO\_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{getpriority} e
+    \func{setpriority} per le tre possibili scelte.}
+  \label{tab:proc_getpriority}
+\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.  
+
+Analoga a \func{getpriority} la funzione \func{setpriority} permette di
+settare la priorità di uno o più processi; il suo prototipo è:
+\begin{prototype}{sys/resource.h}
+{int setpriority(int which, int who, int prio)}  
+  Setta la priorità per l'insieme dei processi specificati.
+
+  \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} può assumere i valori:
+  \begin{errlist}
+  \item[\macro{ESRCH}] non c'è nessun processo che corrisponda ai valori di
+  \param{which} e \param{who}.
+  \item[\macro{EINVAL}] il valore di \param{which} non è valido.
+  \item[\macro{EPERM}] un processo senza i privilegi di amministratore ha
+    specificato un valore di \param{inc} negativo.
+  \item[\macro{EACCESS}] un processo senza i privilegi di amministratore ha
+    cercato di modificare la priorità di un processo di un altro utente.
+  \end{errlist}}
+\end{prototype}
+
+La funzione setta la priorità al valore specificato da \param{prio} per tutti
+i processi indicati dagli argomenti \param{which} e \param{who}.  La gestione
+dei permessi dipende dalle varie implementazioni; in Linux, secondo le
+specifiche dello standard SUSv3, e come avviene per tutti i sistemi che
+derivano da SYSV, è richiesto che il real o l'effective user id del processo
+chiamante corrispondano al real user id (e solo quello) del processo di cui si
+vuole cambiare la priorità; per i sistemi derivati da BSD invece (SunOS,
+Ultrix, *BSD) la corrispondenza può essere anche con l'effective user id.
 
 
 
 \subsection{Il meccanismo di \textit{scheduling real-time}}
 \label{sec:proc_real_time}
 
-Per settare le 
+Come spiegato in \secref{sec:proc_sched} lo standard POSIX.1b ha introdotto le
+priorità assolute per permettere la gestione di processi real-time. In realtà
+nel caso di Linux non si tratta di un vero hard real-time, in quanto in
+presenza di eventuali interrupt il kernel interrompe l'esecuzione di un
+processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si
+  siano installate le patch di RTLinux o RTAI, con i quali è possibile
+  ottenere un sistema effettivamente hard real-time. In tal caso infatti gli
+  interrupt vengono intercettati dall'interfaccia real-time, e gestiti
+  direttamente qualora ci sia la necessità di avere un processo con priorità
+  più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
+page fault si possono avere ritardi non previsti. Se l'ultimo problema può
+essere aggirato attraverso l'uso delle funzioni di controllo della memoria
+virtuale (vedi \secref{sec:proc_mem_lock}), il primo non è superabile e può
+comportare ritardi non prevedibili riguardo ai tempi di esecuzione di
+qualunque processo.
+
+In ogni caso occorre usare le priorità assolute con molta attenzione: se si dà
+ad un processo una priorità assoluta e questo finisce in un loop infinito,
+nessun altro processo potrà essere eseguito, ed esso sarà mantenuto in
+esecuzione permanentemente assorbendo tutta la CPU e senza nessuna possibilità
+di riottenere l'accesso al sistema. Per questo motivo è sempre opportuno,
+quando si lavora con processi che usano priorità assolute, tenere attiva una
+shell cui si sia assegnata la massima priorità assoluta, in modo da poter
+essere comunque in grado di rientrare nel sistema.
+
+Quando c'è un processo con priorità assoluta lo scheduler lo metterà in
+esecuzione prima di ogni processo normale. In caso di più processi sarà
+eseguito per primo quello con priorità assoluta più alta. Quando ci sono più
+processi con la stessa priorità assoluta questi vengono tenuti in una coda
+tocca al kernel decidere quale deve essere eseguito. 
+
+
+
+Il meccanismo con cui vengono gestiti questi processi dipende dalla politica
+di scheduling che si è scelto; lo standard ne prevede due:
+\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}}
+\item[\textit{FIFO}] il processo viene eseguito fintanto che non cede
+  volontariamente la CPU, si blocca, finisce o viene interrotto da un processo
+  a priorità più alta.
+\item[\textit{Round Robin}] ciascun processo viene eseguito a turno per un
+  certo periodo di tempo (una \textit{time slice}). Solo i processi con la
+  stessa priorità ed in stato \textit{runnable} entrano nel circolo.
+\end{basedescript}
+
+La funzione per settare le politiche di scheduling (sia real-time che
+ordinarie) ed i relativi parametri è \func{sched\_setscheduler}; il suo
+prototipo è:
+\begin{prototype}{sched.h}
+{int sched\_setscheduler(pid\_t pid, int policy, const struct sched\_param *p)}
+  Setta priorità e politica di scheduling per il processo \param{pid}.
+
+  \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\macro{ESRCH}] il processo \param{pid} non esiste.
+    \item[\macro{EINVAL}] il valore di \param{policy} non esiste o il relativo
+      valore di \param{p} non è valido.
+    \item[\macro{EPERM}] il processo non ha i privilegi per attivare la
+      politica richiesta (vale solo per \macro{SCHED\_FIFO} e
+      \macro{SCHED\_RR}).
+  \end{errlist}}
+\end{prototype}
+
+La funzione esegue il settaggio per il processo specificato; un valore nullo
+di \param{pid} esegue il settaggio per il processo corrente, solo un processo
+con i privilegi di amministratore può settare delle priorità assolute diverse
+da zero. La politica di scheduling è specificata dall'argomento \param{policy}
+i cui possibili valori sono riportati in \tabref{tab:proc_sched_policy}; un
+valore negativo per \param{policy} mantiene la politica di scheduling
+corrente.
 
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|c|l|}
+    \hline
+    \textbf{Policy}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{SCHED\_FIFO} & Scheduling real-time con politica \textit{FIFO} \\
+    \macro{SCHED\_RR}   & Scheduling real-time con politica \textit{Round
+    Robin} \\
+    \macro{SCHED\_OTHER}& Scheduling ordinario\\
+    \hline
+  \end{tabular}
+  \caption{Valori dell'argomento \param{policy}  per la funzione
+    \func{sched\_setscheduler}. }
+  \label{tab:proc_sched_policy}
+\end{table}
 
-\footnote{a meno che non si siano installate le patch di RTLinux o RTAI, con i
-  quali è possibile ottenere un sistema effettivamente hard real-time.}
+Il valore della priorità è passato attraverso la struttura \var{sched\_param}
+(riportata in \figref{fig:sig_sched_param}), il cui solo campo attualmente
+definito è \var{sched\_priority}, che nel caso delle priorità assolute deve
+essere specificato nell'intervallo fra 1 e 99 (il valore zero è legale, ma
+indica i processi normali). Lo standard POSIX.1b prevede comunque che questi
+due valori possano essere ottenuti per ciascuna politica di scheduling dalle
+funzioni \func{sched\_get\_priority\_max} e \func{sched\_get\_priority\_min},
+i cui prototipi sono:
+\begin{functions}
+  \headdecl{sched.h}
+  
+  \funcdecl{int sched\_get\_priority\_max(int policy)} Legge il valore
+  massimo della priorità statica per la politica di scheduling \param{policy}.
+
+  
+  \funcdecl{int sched\_get\_priority\_min(int policy)} Legge il valore minimo
+  della priorità statica per la politica di scheduling \param{policy}.
+  
+  \bodydesc{La funzioni ritornano il valore della priorità in caso di successo
+    e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\macro{EINVAL}] il valore di \param{policy} è invalido.
+  \end{errlist}}
+\end{functions}
 
-in realtà non si tratta di un vero hard real-time, in quanto
-  la presenza di eventuali interrupt o di page fault può sempre interrompere
-  l'esecuzione di un processo, a meno di non installare le estensioni di
-  RTLinux o RTAI, il normale kernel non è real-time.
 
+I processi con politica di scheduling \macro{SCHED\_OTHER} devono specificare
+un valore nullo (altrimenti si avrà un errore \macro{EINVAL}), questo valore
+infatti non ha niente a che vedere con la priorità dinamica determinata dal
+valore di \var{nice}, che deve essere settato con le funzioni viste in
+precedenza.
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct sched_param {
+    int sched_priority;
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \var{sched\_param}.} 
+  \label{fig:sig_sched_param}
+\end{figure}
 
+Il kernel mantiene i processi con la stessa priorità assoluta in una lista, ed
+esegue sempre il primo della lista, mentre un nuovo processo che torna in
+stato \textit{runnable} viene sempre inserito in coda alla lista. Se la
+politica scelta è \macro{SCHED\_FIFO} quando il processo viene eseguito viene
+automaticamente rimesso in coda alla lista, e la sua esecuzione continua
+fintanto che non viene bloccato da una richiesta di I/O, o non rilascia
+volontariamente la CPU (in tal caso, tornando nello stato \textit{runnable}
+sarà reinserito in coda alla lista); l'esecuzione viene ripresa subito solo
+nel caso che esso sia stato interrotto da un processo a priorità più alta.
+
+La priorità assoluta può essere riletta indietro dalla funzione
+\func{sched\_getscheduler}, il cui prototipo è:
+\begin{prototype}{sched.h}
+{int sched\_getscheduler(pid\_t pid)}
+  Legge la politica di scheduling per il processo \param{pid}.
+  
+  \bodydesc{La funzione ritorna la politica di scheduling in caso di successo
+    e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\macro{ESRCH}] il processo \param{pid} non esiste.
+    \item[\macro{EINVAL}] il valore di \param{pid} è negativo.
+  \end{errlist}}
+\end{prototype}
+
+La funzione restituisce il valore (secondo la quanto elencato in
+\tabref{tab:proc_sched_policy}) della politica di scheduling per il processo
+specificato; se \param{pid} è nullo viene restituito quello del processo
+chiamante.
+
+Se si intende operare solo sulla priorità assoluta di un processo si possono
+usare le funzioni \func{sched\_setparam} e \func{sched\_getparam}, i cui
+prototipi sono:
+  
+\begin{functions}
+  \headdecl{sched.h}
+
+  \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)}
+  Setta la priorità assoluta del processo \param{pid}.
+
+
+  \funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)}
+  Legge la priorità assoluta del processo \param{pid}.
+
+  \bodydesc{La funzione ritorna la priorità  in caso di successo
+    e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\macro{ESRCH}] il processo \param{pid} non esiste.
+    \item[\macro{EINVAL}] il valore di \param{pid} è negativo.
+  \end{errlist}}
+\end{functions}
+
+L'uso di \func{sched\_setparam} che è del tutto equivalente a
+\func{sched\_setscheduler} con \param{priority} uguale a -1. Come per
+\func{sched\_setscheduler} specificando 0 come valore di \param{pid} si opera
+sul processo corrente. La disponibilità di entrambe le funzioni può essere
+verificata controllando la macro \macro{\_POSIX\_PRIORITY\_SCHEDULING} che è
+definita nell'header \macro{sched.h}.
+
+L'ultima funzione che permette di leggere le informazioni relative ai processi
+real-time è \func{sched\_rr\_get\_interval}, che permette di ottenere la
+lunghezza della \textit{time slice} usata dalla politica \textit{round robin};
+il suo prototipo è:
+\begin{prototype}{sched.h}
+  {int sched\_rr\_get\_interval(pid\_t pid, struct timespec *tp)} Legge in
+  \param{tp} la durata della \textit{time slice} per il processo \param{pid}.
+  
+  \bodydesc{La funzione ritorna 0in caso di successo e -1 in caso di errore,
+    nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\macro{ESRCH}] il processo \param{pid} non esiste.
+    \item[\macro{ENOSYS}] la system call non è stata implementata.
+  \end{errlist}}
+\end{prototype}
+
+La funzione restituisce il valore dell'intervallo di tempo usato per la
+politica \textit{round robin} in una struttura \var{timespec}, (la cui
+definizione si può trovare in \secref{fig:sig_timespec_def}).
+
+
+Come accennato ogni processo che usa lo scheduling real-time può rilasciare
+volontariamente la CPU; questo viene fatto attraverso la funzione
+\func{sched\_yield}, il cui prototipo è:
+\begin{prototype}{sched.h}
+  {int sched\_yield(void)} 
+  
+  Rilascia volontariamente l'esecuzione.
+  
+  \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
+    nel qual caso \var{errno} viene settata opportunamente.}
+\end{prototype}
+
+La funzione fa si che il processo rilasci la CPU, in modo da essere rimesso in
+coda alla lista dei processi da eseguire, e permettere l'esecuzione di un
+altro processo; 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 l'esecuzione degli altri processi
+con pari priorità quando la sezione più urgente è finita.
 
 
 \section{Problematiche di programmazione multitasking}
@@ -1985,19 +2371,20 @@ qualunque momento, e le operazioni di un eventuale \textit{signal handler}
 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
-\secref{sec:sign_control}).
+\secref{sec:sig_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ò
 assumere che, in ogni piattaforma su cui è implementato Linux, il tipo
-\type{int}, gli altri interi di dimensione inferiore ed i puntatori sono
+\ctyp{int}, gli altri interi di dimensione inferiore ed i puntatori sono
 atomici. Non è affatto detto che lo stesso valga per interi di dimensioni
 maggiori (in cui l'accesso può comportare più istruzioni in assembler) o per
 le strutture. In tutti questi casi è anche opportuno marcare come
-\type{volatile} le variabili che possono essere interessate ad accesso
+\ctyp{volatile} le variabili che possono essere interessate ad accesso
 condiviso, onde evitare problemi con le ottimizzazioni del codice.
 
 
+
 \subsection{Le \textit{race condition} e i \textit{deadlock}}
 \label{sec:proc_race_cond}
 
@@ -2019,7 +2406,7 @@ funzioner
 
 Per questo occorre essere ben consapevoli di queste problematiche, e del fatto
 che l'unico modo per evitarle è quello di riconoscerle come tali e prendere
-gli adeguati provvedimenti per far si che non si verifichino. Casi tipici di
+gli adeguati provvedimenti per far sì che non si verifichino. Casi tipici di
 \textit{race condition} si hanno quando diversi processi accedono allo stesso
 file, o nell'accesso a meccanismi di intercomunicazione come la memoria
 condivisa. In questi casi, se non si dispone della possibilità di eseguire
@@ -2065,12 +2452,12 @@ 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
 ogni volta e ritornato indietro la funzione può essere rientrante, se invece
-esso viene individuato dalla funzione stessa, due chiamate alla stessa
-funzione potranno interferire quando entrambe faranno riferimento allo stesso
-oggetto.  Allo stesso modo una funzione può non essere rientrante se usa e
-modifica un oggetto che le viene fornito dal chiamante: due chiamate possono
-interferire se viene passato lo stesso oggetto; in tutti questi casi occorre
-molta cura da parte del programmatore.
+esso viene individuato dalla funzione stessa due chiamate alla stessa funzione
+potranno interferire quando entrambe faranno riferimento allo stesso oggetto.
+Allo stesso modo una funzione può non essere rientrante se usa e modifica un
+oggetto che le viene fornito dal chiamante: due chiamate possono interferire
+se viene passato lo stesso oggetto; in tutti questi casi occorre molta cura da
+parte del programmatore.
 
 In genere le funzioni di libreria non sono rientranti, molte di esse ad
 esempio utilizzano variabili statiche, le \acr{glibc} però mettono a