+\label{sec:proc_perms}
+
+In questa sezione esamineremo le problematiche relative al controllo di
+accesso dal punto di vista del processi; vedremo quali sono gli identificatori
+usati, come questi possono essere modificati nella creazione e nel lancio di
+nuovi processi, le varie funzioni per la loro manipolazione diretta e tutte le
+problematiche connesse ad una gestione accorta dei privilegi.
+
+
+\subsection{Gli identificatori del controllo di accesso}
+\label{sec:proc_access_id}
+
+Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in
+ realtà già esistono estensioni di questo modello base, che lo rendono più
+ flessibile e controllabile, come le \textit{capabilities}, le ACL per i file
+ o il \textit{Mandatory Access Control} di SELinux.} 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.
+
+%Benché il sistema sia piuttosto semplice (è basato su un solo livello di
+% separazione) il sistema permette una
+%notevole flessibilità,
+
+Abbiamo già accennato come il sistema associ ad ogni utente e gruppo due
+identificatori univoci, lo \acr{uid} e il \acr{gid}; questi servono al kernel
+per identificare uno specifico utente o un gruppo di utenti, per poi poter
+controllare che essi siano autorizzati a compiere le operazioni richieste. Ad
+esempio in \secref{sec:file_access_control} vedremo come ad ogni file vengano
+associati un utente ed un gruppo (i suoi \textsl{proprietari}, indicati
+appunto tramite un \acr{uid} ed un \acr{gid}) che vengono controllati dal
+kernel nella gestione dei permessi di accesso.
+
+Dato che tutte le operazioni del sistema vengono compiute dai processi, è
+evidente che per poter implementare un controllo sulle operazioni occorre
+anche poter identificare chi è che ha lanciato un certo programma, e pertanto
+anche a ciascun processo è associato un utente e a un gruppo.
+
+Un semplice controllo di una corrispondenza fra identificativi non garantisce
+però sufficiente flessibilità per tutti quei casi in cui è necessario poter
+disporre di privilegi diversi, o dover impersonare un altro utente per un
+limitato insieme di operazioni. Per questo motivo in generale tutti gli Unix
+prevedono che i processi abbiano almeno due gruppi di identificatori, chiamati
+rispettivamente \textit{real} ed \textit{effective}.
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|l|p{6.5cm}|}
+ \hline
+ \textbf{Suffisso} & \textbf{Significato} & \textbf{Utilizzo} \\
+ \hline
+ \hline
+ \acr{uid} & \textit{real user id} & indica l'utente che ha lanciato
+ il programma\\
+ \acr{gid} & \textit{real group id} & indica il gruppo dell'utente
+ che ha lanciato il programma \\
+ \hline
+ \acr{euid} & \textit{effective user id} & indica l'utente usato
+ dal programma nel controllo di accesso \\
+ \acr{egid} & \textit{effective group id} & indica il gruppo
+ usato dal programma nel controllo di accesso \\
+ -- & \textit{supplementary group id} & indica i gruppi cui
+ l'utente appartiene \\
+ \hline
+ -- & \textit{saved user id} & copia dell'\acr{euid} iniziale\\
+ -- & \textit{saved group id} & copia dell'\acr{egid} iniziale \\
+ \hline
+ \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per
+ il filesystem \\
+ \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo
+ per il filesystem \\
+ \hline
+ \end{tabular}
+ \caption{Identificatori di utente e gruppo associati a ciascun processo con
+ indicazione dei suffissi usati dalle varie funzioni di manipolazione.}
+ \label{tab:proc_uid_gid}
+\end{table}
+
+Al primo gruppo appartengono il \textit{real user id} e il \textit{real group
+ id}: questi vengono settati al login ai valori corrispondenti all'utente con
+cui si accede al sistema (e relativo gruppo di default). Servono per
+l'identificazione dell'utente e normalmente non vengono mai cambiati. In
+realtà vedremo (in \secref{sec:proc_setuid}) che è possibile modificarli, ma
+solo ad un processo che abbia i privilegi di amministratore; questa
+possibilità è usata ad esempio da \cmd{login} che, una volta completata la
+procedura di autenticazione, lancia una shell per la quale setta questi
+identificatori ai valori corrispondenti all'utente che entra nel sistema.
+
+Al secondo gruppo appartengono l'\textit{effective user id} e
+l'\textit{effective group id} (a cui si aggiungono gli eventuali
+\textit{supplementary group id} dei gruppi dei quali l'utente fa parte).
+Questi sono invece gli identificatori usati nella verifiche dei permessi del
+processo e per il controllo di accesso ai file (argomento affrontato in
+dettaglio in \secref{sec:file_perm_overview}).
+
+Questi identificatori normalmente sono identici ai corrispondenti del gruppo
+\textit{real} tranne nel caso in cui, come accennato in
+\secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
+\acr{suid} o \acr{sgid} settati (il significato di questi bit è affrontato in
+dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno settati
+all'utente e al gruppo proprietari del file. Questo consente, per programmi in
+cui ci sia necessità, di dare a qualunque utente normale privilegi o permessi
+di un'altro (o dell'amministratore).
+
+Come nel caso del \acr{pid} e del \acr{ppid} tutti questi identificatori
+possono essere letti dal processo attraverso delle opportune funzioni, i cui
+prototipi sono i seguenti:
+\begin{functions}
+ \headdecl{unistd.h}
+ \headdecl{sys/types.h}
+ \funcdecl{uid\_t getuid(void)} Restituisce il \textit{real user id} del
+ processo corrente.
+
+ \funcdecl{uid\_t geteuid(void)} Restituisce l'\textit{effective user id} del
+ processo corrente.
+
+ \funcdecl{gid\_t getgid(void)} Restituisce il \textit{real group id} del
+ processo corrente.
+
+ \funcdecl{gid\_t getegid(void)} Restituisce l'\textit{effective group id} del
+ processo corrente.
+
+ \bodydesc{Queste funzioni non riportano condizioni di errore.}
+\end{functions}
+
+In generale l'uso di privilegi superiori deve essere limitato il più
+possibile, per evitare abusi e problemi di sicurezza, per questo occorre anche
+un meccanismo che consenta ad un programma di rilasciare gli eventuali
+maggiori privilegi necessari, una volta che si siano effettuate le operazioni
+per i quali erano richiesti, e a poterli eventualmente recuperare in caso
+servano di nuovo.
+
+Questo in Linux viene fatto usando altri due gruppi di identificatori, il
+\textit{saved} ed il \textit{filesystem}, analoghi ai precedenti. Il primo
+gruppo è lo stesso usato in SVr4, e previsto dallo standard POSIX quando è
+definita la costante \macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a
+ cuore la portabilità del programma su altri Unix è buona norma controllare
+ sempre la disponibilità di queste funzioni controllando se questa costante è
+ definita.} il secondo gruppo è specifico di Linux e viene usato per
+migliorare la sicurezza con NFS.
+
+Il \textit{saved user id} e il \textit{saved group id} sono copie
+dell'\textit{effective user id} e dell'\textit{effective group id} del
+processo padre, e vengono settati dalla funzione \func{exec} all'avvio del
+processo, come copie dell'\textit{effective user id} e dell'\textit{effective
+ group id} dopo che questo sono stati settati tenendo conto di eventuali
+\acr{suid} o \acr{sgid}. Essi quindi consentono di tenere traccia di quale
+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
+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
+saranno del tutto equivalenti ai precedenti.
+
+Uno specchietto riassuntivo, contenente l'elenco completo degli identificatori
+di utente e gruppo associati dal kernel ad ogni processo, è riportato in
+\tabref{tab:proc_uid_gid}.
+
+
+\subsection{Le funzioni \func{setuid} e \func{setgid}}
+\label{sec:proc_setuid}
+
+Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo
+di appartenenza) ad un processo sono rispettivamente \func{setuid} e
+\func{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse
+seguono la semantica POSIX che prevede l'esistenza del \textit{saved user id}
+e del \textit{saved group id}; i loro prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int setuid(uid\_t uid)} Setta l'\textit{user id} del processo
+corrente.
+
+\funcdecl{int setgid(gid\_t gid)} Setta il \textit{group id} del processo
+corrente.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+ di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\end{functions}
+
+Il funzionamento di queste due funzioni è analogo, per cui considereremo solo
+la prima; la seconda si comporta esattamente allo stesso modo facendo
+riferimento al \textit{group id} invece che all'\textit{user id}. Gli
+eventuali \textit{supplementary group id} non vengono modificati.
+
+
+L'effetto della chiamata è diverso a seconda dei privilegi del processo; se
+l'\textit{effective user id} è zero (cioè è quello dell'amministratore di
+sistema) allora tutti gli identificatori (\textit{real}, \textit{effective}
+e \textit{saved}) vengono settati al valore specificato da \var{uid},
+altrimenti viene settato solo l'\textit{effective user id}, e soltanto se il
+valore specificato corrisponde o al \textit{real user id} o al \textit{saved
+ user id}. Negli altri casi viene segnalato un errore (con \macro{EPERM}).
+
+Come accennato l'uso principale di queste funzioni è quello di poter
+consentire ad un programma con i bit \acr{suid} o \acr{sgid} settati di
+riportare l'\textit{effective user id} a quello dell'utente che ha lanciato il
+programma, effettuare il lavoro che non necessita di privilegi aggiuntivi, 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
+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
+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} settato.
+
+Quando uno di questi programmi (ad esempio \cmd{xterm}) viene lanciato, la
+situazione degli identificatori è la seguente:
+\begin{eqnarray*}
+ \label{eq:1}
+ \textit{real group id} &=& \textrm{\acr{gid} (del chiamante)} \\
+ \textit{effective group id} &=& \textrm{\acr{utmp}} \\
+ \textit{saved group id} &=& \textrm{\acr{utmp}}
+\end{eqnarray*}
+in questo modo, dato che l'\textit{effective group id} è 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 settare
+l'\textit{effective group id} a quello dell'utente (e dato che il \textit{real
+ group id} corrisponde la funzione avrà successo), in questo modo non sarà
+possibile lanciare dal terminale programmi che modificano detto file, in tal
+caso infatti la situazione degli identificatori sarebbe:
+\begin{eqnarray*}
+ \label{eq:2}
+ \textit{real group id} &=& \textrm{\acr{gid} (invariato)} \\
+ \textit{effective group id} &=& \textrm{\acr{gid}} \\
+ \textit{saved group id} &=& \textrm{\acr{utmp} (invariato)}
+\end{eqnarray*}
+e ogni processo lanciato dal terminale avrebbe comunque \acr{gid} come
+\textit{effective group id}. All'uscita dal terminale, per poter di nuovo
+aggiornare lo stato di \file{/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 \textit{saved group id} la
+funzione avrà successo e riporterà la situazione a:
+\begin{eqnarray*}
+ \label{eq:3}
+ \textit{real group id} &=& \textrm{\acr{gid} (invariato)} \\
+ \textit{effective group id} &=& \textrm{\acr{utmp}} \\
+ \textit{saved group id} &=& \textrm{\acr{utmp} (invariato)}
+\end{eqnarray*}
+consentendo l'accesso a \file{/var/log/utmp}.
+
+Occorre però tenere conto che tutto questo non è possibile con un processo con
+i privilegi di root, in tal caso infatti l'esecuzione una \func{setuid}
+comporta il cambiamento di tutti gli identificatori associati al processo,
+rendendo impossibile riguadagnare i privilegi di amministratore. Questo
+comportamento è corretto per l'uso che ne fa \cmd{login} una volta che crea
+una nuova shell per l'utente; ma quando si vuole cambiare soltanto
+l'\textit{effective user id} del processo per cedere i privilegi occorre
+ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}).
+
+
+\subsection{Le funzioni \func{setreuid} e \func{setresuid}}
+\label{sec:proc_setreuid}
+
+Queste due funzioni derivano da BSD che, non supportando\footnote{almeno fino
+ alla versione 4.3+BSD TODO, FIXME verificare e aggiornare la nota.} i
+\textit{saved id}, le usava per poter scambiare fra di loro \textit{effective}
+e \textit{real id}. I loro prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Setta il \textit{real user
+ id} e l'\textit{effective user id} del processo corrente ai valori
+specificati da \var{ruid} e \var{euid}.
+
+\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Setta il \textit{real group
+ id} e l'\textit{effective group id} del processo corrente ai valori
+specificati da \var{rgid} e \var{egid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+ di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\end{functions}
+
+I processi non privilegiati possono settare i \textit{real id} soltanto ai
+valori dei loro \textit{effective id} o \textit{real id} e gli
+\textit{effective id} ai valori dei loro \textit{real id}, \textit{effective
+ id} o \textit{saved id}; valori diversi comportano il fallimento della
+chiamata; l'amministratore invece può specificare un valore qualunque.
+Specificando un valore di -1 l'identificatore corrispondente viene lasciato
+inalterato.
+
+Con queste funzione si possono scambiare fra loro \textit{real id} e
+\textit{effective id}, e pertanto è possibile implementare un comportamento
+simile a quello visto in precedenza per \func{setgid}, cedendo i privilegi con
+un primo scambio, e recuperandoli, eseguito il lavoro non privilegiato, con un
+secondo scambio.
+
+In questo caso però occorre porre molta attenzione quando si creano nuovi
+processi nella fase intermedia in cui si sono scambiati gli identificatori, in
+questo caso infatti essi avranno un \textit{real id} privilegiato, che dovrà
+essere esplicitamente eliminato prima di porre in esecuzione un nuovo
+programma (occorrerà cioè eseguire un'altra chiamata dopo la \func{fork}, e
+prima della \func{exec} per uniformare i \textit{real id} agli
+\textit{effective id}) in caso contrario quest'ultimo potrebbe a sua volta
+effettuare uno scambio e riottenere privilegi non previsti.
+
+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 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}.
+
+
+
+\subsection{Le funzioni \func{seteuid} e \func{setegid}}
+\label{sec:proc_seteuid}
+
+Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque
+supportate dalla maggior parte degli Unix) e usate per cambiare gli
+\textit{effective id}; i loro prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int seteuid(uid\_t uid)} Setta l'\textit{effective user id} del
+processo corrente a \var{uid}.
+
+\funcdecl{int setegid(gid\_t gid)} Setta l'\textit{effective group id} del
+processo corrente a \var{gid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+ di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\end{functions}
+
+Gli utenti normali possono settare l'\textit{effective id} solo al valore del
+\textit{real id} o del \textit{saved id}, l'amministratore può specificare
+qualunque valore. Queste funzioni sono usate per permettere a root di settare
+solo l'\textit{effective id}, dato che l'uso normale di \func{setuid} comporta
+il settaggio di tutti gli identificatori.
+
+
+\subsection{Le funzioni \func{setresuid} e \func{setresgid}}
+\label{sec:proc_setresuid}
+
+Queste due funzioni sono un'estensione introdotta in Linux dal kernel 2.1.44,
+e permettono un completo controllo su tutti gli identificatori (\textit{real},
+\textit{effective} e \textit{saved}), i prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Setta il
+\textit{real user id}, l'\textit{effective user id} e il \textit{saved user
+ id} del processo corrente ai valori specificati rispettivamente da
+\var{ruid}, \var{euid} e \var{suid}.
+
+\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Setta il
+\textit{real group id}, l'\textit{effective group id} e il \textit{saved group
+ id} del processo corrente ai valori specificati rispettivamente da
+\var{rgid}, \var{egid} e \var{sgid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+ di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\end{functions}
+
+I processi non privilegiati possono cambiare uno qualunque degli
+identificatori usando uno qualunque dei valori correnti di \textit{real id},
+\textit{effective id} o \textit{saved id}, l'amministratore può specificare i
+valori che vuole; un valore di -1 per un qualunque parametro lascia inalterato
+l'identificatore corrispondente.
+
+Per queste funzioni esistono anche due controparti che permettono di leggere
+in blocco i vari identificatori: \func{getresuid} e \func{getresgid}; i loro
+prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int getresuid(uid\_t *ruid, uid\_t *euid, uid\_t *suid)} Legge il
+\textit{real user id}, l'\textit{effective user id} e il \textit{saved user
+ id} del processo corrente.
+
+\funcdecl{int getresgid(gid\_t *rgid, gid\_t *egid, gid\_t *sgid)} Legge il
+\textit{real group id}, l'\textit{effective group id} e il \textit{saved group
+ id} del processo corrente.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di
+ fallimento: l'unico errore possibile è \macro{EFAULT} se gli indirizzi delle
+ variabili di ritorno non sono validi.}
+\end{functions}
+
+Anche queste funzioni sono un'estensione specifica di Linux, e non richiedono
+nessun privilegio. I valori sono restituiti negli argomenti, che vanno
+specificati come puntatori (è un'altro esempio di \textit{value result
+ argument}). Si noti che queste funzioni sono le uniche in grado di leggere i
+\textit{saved id}.
+
+
+\subsection{Le funzioni \func{setfsuid} e \func{setfsgid}}
+\label{sec:proc_setfsuid}
+
+Queste funzioni sono usate per settare gli identificatori usati da Linux per
+il controllo dell'accesso ai file. Come già accennato in
+\secref{sec:proc_access_id} in Linux è definito questo ulteriore gruppo di
+identificatori, che di norma sono assolutamente equivalenti agli
+\textit{effective id}, dato che ogni cambiamento di questi ultimi viene
+immediatamente riportato sui \textit{filesystem id}.
+
+C'è un solo caso in cui si ha necessità di introdurre una differenza fra
+\textit{effective id} e \textit{filesystem id}, ed è per ovviare ad un
+problema di sicurezza che si presenta quando si deve implementare un server
+NFS. Il server NFS infatti deve poter cambiare l'identificatore con cui accede
+ai file per assumere l'identità del singolo utente remoto, ma se questo viene
+fatto cambiando l'\textit{effective id} o il \textit{real id} il server si
+espone alla ricezione di eventuali segnali ostili da parte dell'utente di cui
+ha temporaneamente assunto l'identità. Cambiando solo il \textit{filesystem
+ id} si ottengono i privilegi necessari per accedere ai file, mantenendo
+quelli originari per quanto riguarda tutti gli altri controlli di accesso,
+così che l'utente non possa inviare segnali al server NFS.
+
+Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid}
+e \func{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
+usate se si intendono scrivere programmi portabili; i loro prototipi sono:
+\begin{functions}
+\headdecl{sys/fsuid.h}
+
+\funcdecl{int setfsuid(uid\_t fsuid)} Setta il \textit{filesystem user id} del
+processo corrente a \var{fsuid}.
+
+\funcdecl{int setfsgid(gid\_t fsgid)} Setta l'\textit{filesystem group id} del
+processo corrente a \var{fsgid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+ di fallimento: l'unico errore possibile è \macro{EPERM}.}
+\end{functions}
+\noindent queste funzioni hanno successo solo se il processo chiamante ha i
+privilegi di amministratore o, per gli altri utenti, se il valore specificato
+coincide con uno dei \textit{real}, \textit{effective} o \textit{saved id}.
+
+
+\subsection{Le funzioni \func{setgroups} e \func{getgroups}}
+\label{sec:proc_setgroups}
+
+Le ultime funzioni che esamineremo sono quelle che permettono di operare sui
+gruppi supplementari. Ogni processo può avere fino a \macro{NGROUPS\_MAX}
+gruppi supplementari in aggiunta al gruppo primario, questi vengono ereditati
+dal processo padre e possono essere cambiati con queste funzioni.
+
+La funzione che permette di leggere i gruppi supplementari è \func{getgroups};
+questa funzione è definita nello standard POSIX ed il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{unistd.h}
+
+ \funcdecl{int getgroups(int size, gid\_t list[])} Legge gli identificatori
+ dei gruppi supplementari del processo sul vettore \param{list} di dimensione
+ \param{size}.
+
+ \bodydesc{La funzione restituisce il numero di gruppi letti in caso di
+ successo e -1 in caso di fallimento, nel qual caso \var{errno} viene
+ settata a:
+ \begin{errlist}
+ \item[\macro{EFAULT}] \param{list} non ha un indirizzo valido.
+ \item[\macro{EINVAL}] il valore di \param{size} è diverso da zero ma
+ minore del numero di gruppi supplementari del processo.
+ \end{errlist}}
+\end{functions}
+\noindent non è specificato se la funzione inserisca o meno nella lista
+l'\textit{effective user id} del processo. Se si specifica un valore di
+\param{size} uguale a 0 \param{list} non viene modificato, ma si ottiene il
+numero di gruppi supplementari.
+
+Una seconda funzione, \func{getgrouplist}, può invece essere usata per
+ottenere tutti i gruppi a cui appartiene un utente; il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{grp.h}
+
+ \funcdecl{int getgrouplist(const char *user, gid\_t group, gid\_t *groups,
+ int *ngroups)} Legge i gruppi supplementari dell'utente \param{user}.
+
+ \bodydesc{La funzione legge fino ad un massimo di \param{ngroups} valori,
+ restituisce 0 in caso di successo e -1 in caso di fallimento.}
+\end{functions}
+\noindent la funzione esegue una scansione del database dei gruppi (si veda
+\secref{sec:sys_user_group}) e ritorna in \param{groups} la lista di quelli a
+cui l'utente appartiene. Si noti che \param{ngroups} è passato come puntatore
+perché qualora il valore specificato sia troppo piccolo la funzione ritorna
+-1, passando indietro il numero dei gruppi trovati.
+
+Per settare i gruppi supplementari di un processo ci sono due funzioni, che
+possono essere usate solo se si hanno i privilegi di amministratore. La prima
+delle due è \func{setgroups}, ed il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{grp.h}
+
+ \funcdecl{int setgroups(size\_t size, gid\_t *list)} Setta i gruppi
+ supplementari del processo ai valori specificati in \param{list}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ fallimento, nel qual caso \var{errno} viene settata a:
+ \begin{errlist}
+ \item[\macro{EFAULT}] \param{list} non ha un indirizzo valido.
+ \item[\macro{EPERM}] il processo non ha i privilegi di amministratore.
+ \item[\macro{EINVAL}] il valore di \param{size} è maggiore del valore
+ massimo (\macro{NGROUPS}, che per Linux è 32).
+ \end{errlist}}
+\end{functions}
+
+Se invece si vogliono settare i gruppi supplementari del processo a quelli di
+un utente specifico, si può usare \func{initgroups} il cui prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{grp.h}
+
+ \funcdecl{int initgroups(const char *user, gid\_t group)} Setta i gruppi
+ supplementari del processo a quelli di cui è membro l'utente \param{user},
+ aggiungendo il gruppo addizionale \param{group}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ fallimento, nel qual caso \var{errno} viene settata agli stessi valori di
+ \func{setgroups} più \macro{ENOMEM} quando non c'è memoria sufficiente per
+ allocare lo spazio per informazioni dei gruppi.}
+\end{functions}
+
+La funzione esegue la scansione del database dei gruppi (usualmente
+\file{/etc/groups}) cercando i gruppi di cui è membro \param{user} e
+costruendo una lista di gruppi supplementari a cui aggiunge \param{group}, che
+poi setta usando \func{setgroups}.
+
+Si tenga presente che sia \func{setgroups} che \func{initgroups} non sono
+definite nello standard POSIX.1 e che pertanto non è possibile utilizzarle
+quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag
+\cmd{-ansi}.
+
+
+\section{La gestione della priorità di esecuzione}
+\label{sec:proc_priority}
+
+In questa sezione tratteremo più approfonditamente i meccanismi con il quale
+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}}
+\label{sec:proc_sched}
+
+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 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 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 portranno
+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 corripondente 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à
+ dinamiche}, in modo da assicurare che tutti i processi, anche i meno
+importanti, possano ricevere un po' di tempo di CPU. In sostanza quando un
+processo ottiene la CPU la sua priorità viene diminuita. In questo modo alla
+fine, anche un processo con priorità iniziale molto bassa, finisce per avere
+una priorità sufficiente per essere eseguito.
+
+Lo standard POSIX.1b però ha introdotto il concetto di \textsl{priorità
+ assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione
+alla normale priorità dinamica), per tenere conto dei sistemi
+real-time,\footnote{per sistema real-time si intende un sistema in grado di
+ eseguire operazioni in un tempo ben determinato; in genere si tende a
+ distinguere fra l'\textit{hard real-time} in cui è necessario che i tempi di
+ esecuzione di un programma siano determinabili con certezza assoluta (come
+ nel caso di meccanismi di controllo di macchine, dove uno sforamento dei
+ tempi avrebbe conseguenze disastrose), e \textit{soft-real-time} in cui un
+ occasionale sforamento è ritenuto accettabile.} in cui è vitale che i
+processi che devono essere eseguiti in un determinato momento non debbano
+aspettare la conclusione di altri che non hanno questa necessità.
+
+Il concetto di priorità assoluta dice che quando due processi si contendono
+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}). 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 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}
+
+A meno che non si abbiano esigenze specifiche, l'unico meccanismo di
+scheduling con il quale si avrà a che fare è quello tradizionale, che prevede
+solo priorità dinamiche. È di questo che, di norma, ci si dovrà preoccupare
+nella programmazione.
+
+Come accennato in Linux tutti i processi ordinari hanno la stessa priorità
+assoluta. Quello che determina quale, fra tutti i processi in attesa di
+esecuzione, sarà eseguito per primo, è la priorità dinamica, che è chiamata
+così proprio perché varia nel corso dell'esecuzione di un processo. Oltre a
+questo la priorità dinamica determina quanto a lungo un processo continuerà ad
+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 prorità; 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}
+
+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 vegono 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}
+
+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}
+
+
+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 protototipo è:
+\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'esecuzioni degli altri processi
+con pari priorità quando la sezione più urgente è finita.
+
+
+\section{Problematiche di programmazione multitasking}
+\label{sec:proc_multi_prog}
+
+Benché i processi siano strutturati in modo da apparire il più possibile come
+indipendenti l'uno dall'altro, nella programmazione in un sistema multitasking
+occorre tenere conto di una serie di problematiche che normalmente non
+esistono quando si ha a che fare con un sistema in cui viene eseguito un solo
+programma alla volta.
+
+Pur essendo questo argomento di carattere generale, ci è parso opportuno
+introdurre sinteticamente queste problematiche, che ritroveremo a più riprese
+in capitoli successivi, in questa sezione conclusiva del capitolo in cui
+abbiamo affrontato la gestione dei processi.
+
+
+\subsection{Le operazioni atomiche}
+\label{sec:proc_atom_oper}
+
+La nozione di \textsl{operazione atomica} deriva dal significato greco della
+parola atomo, cioè indivisibile; si dice infatti che un'operazione è atomica
+quando si ha la certezza che, qualora essa venga effettuata, tutti i passaggi
+che devono essere compiuti per realizzarla verranno eseguiti senza possibilità
+di interruzione in una fase intermedia.
+
+In un ambiente multitasking il concetto è essenziale, dato che un processo può
+essere interrotto in qualunque momento dal kernel che mette in esecuzione un
+altro processo o dalla ricezione di un segnale; occorre pertanto essere
+accorti nei confronti delle possibili \textit{race condition} (vedi
+\secref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase in
+cui non erano ancora state completate.
+
+Nel caso dell'interazione fra processi la situazione è molto più semplice, ed
+occorre preoccuparsi della atomicità delle operazioni solo quando si ha a che
+fare con meccanismi di intercomunicazione (che esamineremo in dettaglio in
+\capref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in
+\secref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate
+funzioni di libreria per compiere le operazioni necessarie è garanzia
+sufficiente di atomicità in quanto le system call con cui esse sono realizzate
+non possono essere interrotte (o subire interferenze pericolose) da altri
+processi.
+
+Nel caso dei segnali invece la situazione è molto più delicata, in quanto lo
+stesso processo, e pure alcune system call, possono essere interrotti in
+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: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
+\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
+\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}
+
+Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
+diversi operano su una risorsa comune, ed in cui il risultato viene a
+dipendere dall'ordine in cui essi effettuano le loro operazioni. Il caso
+tipico è quello di un'operazione che viene eseguita da un processo in più
+passi, e può essere compromessa dall'intervento di un altro processo che
+accede alla stessa risorsa quando ancora non tutti i passi sono stati
+completati.
+
+Dato che in un sistema multitasking ogni processo può essere interrotto in
+qualunque momento per farne subentrare un'altro in esecuzione, niente può
+assicurare un preciso ordine di esecuzione fra processi diversi o che una
+sezione di un programma possa essere eseguita senza interruzioni da parte di
+altri. Queste situazioni comportano pertanto errori estremamente subdoli e
+difficili da tracciare, in quanto nella maggior parte dei casi tutto
+funzionerà regolarmente, e solo occasionalmente si avranno degli errori.
+
+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 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
+atomicamente le operazioni necessarie, occorre che quelle parti di codice in
+cui si compiono le operazioni sulle risorse condivise (le cosiddette
+\textsl{sezioni critiche}) del programma, siano opportunamente protette da
+meccanismi di sincronizzazione (torneremo su queste problematiche di questo
+tipo in \secref{sec:ipc_semaph}).
+
+Un caso particolare di \textit{race condition} sono poi i cosiddetti
+\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
+completo di un servizio, e non il fallimento di una singola operazione.
+L'esempio tipico di una situazione che può condurre ad un \textit{deadlock} è
+quello in cui un flag di ``occupazione'' viene rilasciato da un evento
+asincrono (come un segnale o un altro processo) fra il momento in cui lo si è
+controllato (trovandolo occupato) e la successiva operazione di attesa per lo
+sblocco. In questo caso, dato che l'evento di sblocco del flag è avvenuto
+senza che ce ne accorgessimo proprio fra il controllo e la messa in attesa,
+quest'ultima diventerà perpetua (da cui il nome di \textit{deadlock}).
+
+In tutti questi casi è di fondamentale importanza il concetto di atomicità
+visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere
+risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile
+eseguire in maniera atomica le operazioni necessarie.
+
+
+\subsection{Le funzioni rientranti}
+\label{sec:proc_reentrant}
+
+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 manipolatori dei segnali.
+
+Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
+queste infatti vengono allocate nello stack, e un'altra invocazione non fa
+altro che allocarne un'altra copia. Una funzione può non essere rientrante
+quando opera su memoria che non è nello stack. Ad esempio una funzione non è
+mai rientrante se usa una variabile globale o statica.