+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.
+
+Solo un processo con i privilegi di amministratore\footnote{più precisamente
+ con la capacità \const{CAP\_SYS\_NICE}, vedi
+ sez.~\ref{sec:proc_capabilities}.} può impostare senza restrizioni priorità
+assolute diverse da zero o politiche \const{SCHED\_FIFO} e
+\const{SCHED\_RR}. Un utente normale può modificare solo le priorità di
+processi che gli appartengono; è cioè richiesto che l'\ids{UID} effettivo del
+processo chiamante corrisponda all'\ids{UID} reale o effettivo del processo
+indicato con \param{pid}.
+
+Fino al kernel 2.6.12 gli utenti normali non potevano impostare politiche
+\textit{real-time} o modificare la eventuale priorità statica di un loro
+processo. A partire da questa versione è divenuto possibile anche per gli
+utenti normali usare politiche \textit{real-time} fintanto che la priorità
+assoluta che si vuole impostare è inferiore al limite \const{RLIMIT\_RTPRIO}
+(vedi sez.~\ref{sec:sys_resource_limit}) ad essi assegnato.
+
+Unica eccezione a questa possibilità sono i processi \const{SCHED\_IDLE}, che
+non possono cambiare politica di \textit{scheduling} indipendentemente dal
+valore di \const{RLIMIT\_RTPRIO}. Inoltre, in caso di processo già sottoposto
+ad una politica \textit{real-time}, un utente può sempre, indipendentemente
+dal valore di \const{RLIMIT\_RTPRIO}, diminuirne la priorità o portarlo ad una
+politica ordinaria.
+
+Se si intende operare solo sulla priorità statica di un processo si possono
+usare le due funzioni di sistema \funcd{sched\_setparam} e
+\funcd{sched\_getparam} che consentono rispettivamente di impostarne e
+leggerne il valore, i loro prototipi sono:
+
+\begin{funcproto}{
+\fhead{sched.h}
+\fdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *param)}
+\fdesc{Imposta la priorità statica di un processo.}
+\fdecl{int sched\_getparam(pid\_t pid, struct sched\_param *param)}
+\fdesc{Legge la priorità statica di un processo.}
+}
+{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual
+caso \var{errno} assumerà uno dei valori:
+\begin{errlist}
+\item[\errcode{EINVAL}] il valore di \param{param} non ha senso per la
+ politica usata dal processo.
+\item[\errcode{EPERM}] non si hanno privilegi sufficienti per eseguire
+ l'operazione.
+\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+\end{errlist}}
+\end{funcproto}
+
+Le funzioni richiedono di indicare nell'argomento \param{pid} il processo su
+cui operare e usano l'argomento \param{param} per mantenere il valore della
+priorità dinamica. Questo è ancora una struttura \struct{sched\_param} ed
+assume gli stessi valori già visti per \func{sched\_setscheduler}.
+
+L'uso di \func{sched\_setparam}, compresi i controlli di accesso che vi si
+applicano, è del tutto equivalente a quello di \func{sched\_setscheduler} con
+argomento \param{policy} uguale a $-1$. Come per \func{sched\_setscheduler}
+specificando $0$ come valore dell'argomento \param{pid} si opera sul processo
+corrente. Benché la funzione sia utilizzabile anche con processi sottoposti a
+politica ordinaria essa ha senso soltanto per quelli \textit{real-time}, dato
+che per i primi la priorità statica può essere soltanto nulla. La
+disponibilità di entrambe le funzioni può essere verificata controllando la
+macro \macrod{\_POSIX\_PRIORITY\_SCHEDULING} che è definita
+nell'\textit{header file} \headfiled{sched.h}.
+
+Se invece si vuole sapere quale è politica di \textit{scheduling} di un
+processo si può usare la funzione di sistema \funcd{sched\_getscheduler}, il
+cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sched.h}
+\fdecl{int sched\_getscheduler(pid\_t pid)}
+\fdesc{Legge la politica di \textit{scheduling}.}
+}
+{La funzione ritorna la politica di \textit{scheduling} in caso di successo e
+ $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+\begin{errlist}
+ \item[\errcode{EPERM}] non si hanno privilegi sufficienti per eseguire
+ l'operazione.
+ \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+\end{errlist}}
+\end{funcproto}
+
+La funzione restituisce il valore, secondo quanto elencato in
+tab.~\ref{tab:proc_sched_policy}, della politica di \textit{scheduling} per il
+processo specificato dall'argomento \param{pid}, se questo è nullo viene
+restituito il valore relativo al processo chiamante.
+
+L'ultima funzione di sistema che permette di leggere le informazioni relative
+ai processi real-time è \funcd{sched\_rr\_get\_interval}, che permette di
+ottenere la lunghezza della \textit{time-slice} usata dalla politica
+\textit{round robin}; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sched.h}
+\fdecl{int sched\_rr\_get\_interval(pid\_t pid, struct timespec *tp)}
+\fdesc{Legge la durata della \textit{time-slice} per lo \textit{scheduling}
+ \textit{round robin}.}
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+caso \var{errno} assumerà uno dei valori:
+\begin{errlist}
+\item[\errcode{EINVAL}] l'argomento \param{pid} non è valido.
+\item[\errcode{ENOSYS}] la \textit{system call} non è presente (solo per
+ kernel arcaici).
+\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+\end{errlist}
+ed inoltre anche \errval{EFAULT} nel suo significato generico.}
+\end{funcproto}
+
+La funzione restituisce nell'argomento \param{tp} come una struttura
+\struct{timespec}, (la cui definizione si può trovare in
+fig.~\ref{fig:sys_timeval_struct}) il valore dell'intervallo di tempo usato
+per la politica \textit{round robin} dal processo indicato da \ids{PID}. Il
+valore dipende dalla versione del kernel, a lungo infatti questo intervallo di
+tempo era prefissato e non modificabile ad un valore di 150 millisecondi,
+restituito indipendentemente dal \ids{PID} indicato.
+
+Con kernel recenti però è possibile ottenere una variazione della
+\textit{time-slice}, modificando il valore di \textit{nice} del processo
+(anche se questo non incide assolutamente sulla priorità statica) che come
+accennato in precedenza modifica il valore assegnato alla \textit{time-slice}
+di un processo ordinario, che però viene usato anche dai processi
+\textit{real-time}.
+
+Come accennato ogni processo può rilasciare volontariamente la CPU in modo da
+consentire agli altri processi di essere eseguiti; la funzione di sistema che
+consente di fare tutto questo è \funcd{sched\_yield}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sched.h}
+\fdecl{int sched\_yield(void)}
+\fdesc{Rilascia volontariamente l'esecuzione.}
+}
+{La funzione ritorna $0$ in caso di successo e teoricamente $-1$ per un
+ errore, ma su Linux ha sempre successo.}
+\end{funcproto}
+
+
+Questa funzione ha un utilizzo effettivo soltanto quando si usa lo
+\textit{scheduling} \textit{real-time}, e serve a far sì che il processo
+corrente rilasci la CPU, in modo da essere rimesso in coda alla lista dei
+processi con la stessa priorità per permettere ad un altro di essere eseguito;
+se però il processo è l'unico ad essere presente sulla coda l'esecuzione non
+sarà interrotta. In genere usano questa funzione i processi con politica
+\const{SCHED\_FIFO}, per permettere l'esecuzione degli altri processi con pari
+priorità quando la sezione più urgente è finita.
+
+La funzione può essere utilizzata anche con processi che usano lo
+\textit{scheduling} ordinario, ma in questo caso il comportamento non è ben
+definito, e dipende dall'implementazione. Fino al kernel 2.6.23 questo
+comportava che i processi venissero messi in fondo alla coda di quelli attivi,
+con la possibilità di essere rimessi in esecuzione entro breve tempo, con
+l'introduzione del \textit{Completely Fair Scheduler} questo comportamento è
+cambiato ed un processo che chiama la funzione viene inserito nella lista dei
+processi inattivo, con un tempo molto maggiore.\footnote{è comunque possibile
+ ripristinare un comportamento analogo al precedente scrivendo il valore 1
+ nel file \sysctlfile{kernel/sched\_compat\_yield}.}
+
+L'uso delle funzione nella programmazione ordinaria può essere utile e
+migliorare le prestazioni generali del sistema quando si è appena rilasciata
+una risorsa contesa con altri processi, e si vuole dare agli altri una
+possibilità di approfittarne mettendoli in esecuzione, ma chiamarla senza
+necessità, specie se questo avviene ripetutamente all'interno di un qualche
+ciclo, può avere invece un forte impatto negativo per la generazione di
+\itindex{contest~switch} \textit{contest switch} inutili.
+
+
+\subsection{Il controllo dello \textit{scheduler} per i sistemi
+ multiprocessore}
+\label{sec:proc_sched_multiprocess}
+
+\index{effetto~ping-pong|(}
+
+Con il supporto dei sistemi multiprocessore sono state introdotte delle
+funzioni che permettono di controllare in maniera più dettagliata la scelta di
+quale processore utilizzare per eseguire un certo programma. Uno dei problemi
+che si pongono nei sistemi multiprocessore è infatti quello del cosiddetto
+\textsl{effetto ping-pong}. Può accadere cioè che lo \textit{scheduler},
+quando riavvia un processo precedentemente interrotto scegliendo il primo
+processore disponibile, lo faccia eseguire da un processore diverso rispetto a
+quello su cui era stato eseguito in precedenza. Se il processo passa da un
+processore all'altro in questo modo, cosa che avveniva abbastanza di frequente
+con i kernel della seria 2.4.x, si ha l'effetto ping-pong.
+
+Questo tipo di comportamento può generare dei seri problemi di prestazioni;
+infatti tutti i processori moderni utilizzano una memoria interna (la
+\textit{cache}) contenente i dati più usati, che permette di evitare di
+eseguire un accesso (molto più lento) alla memoria principale sulla scheda
+madre. Chiaramente un processo sarà favorito se i suoi dati sono nella cache
+del processore, ma è ovvio che questo può essere vero solo per un processore
+alla volta, perché in presenza di più copie degli stessi dati su più
+processori, non si potrebbe determinare quale di questi ha la versione dei
+dati aggiornata rispetto alla memoria principale.
+
+Questo comporta che quando un processore inserisce un dato nella sua cache,
+tutti gli altri processori che hanno lo stesso dato devono invalidarlo, e
+questa operazione è molto costosa in termini di prestazioni. Il problema
+diventa serio quando si verifica l'effetto ping-pong, in tal caso infatti un
+processo \textsl{rimbalza} continuamente da un processore all'altro e si ha
+una continua invalidazione della cache, che non diventa mai disponibile.
+
+\itindbeg{CPU~affinity}
+
+Per ovviare a questo tipo di problemi è nato il concetto di \textsl{affinità
+ di processore} (o \textit{CPU affinity}); la possibilità cioè di far sì che
+un processo possa essere assegnato per l'esecuzione sempre allo stesso
+processore. Lo \textit{scheduler} dei kernel della serie 2.4.x aveva una
+scarsa \textit{CPU affinity}, e l'effetto ping-pong era comune; con il nuovo
+\textit{scheduler} dei kernel della 2.6.x questo problema è stato risolto ed
+esso cerca di mantenere il più possibile ciascun processo sullo stesso
+processore.
+
+\index{effetto~ping-pong|)}
+
+In certi casi però resta l'esigenza di poter essere sicuri che un processo sia
+sempre eseguito dallo stesso processore,\footnote{quella che viene detta
+ \textit{hard CPU affinity}, in contrasto con quella fornita dallo
+ \textit{scheduler}, detta \textit{soft CPU affinity}, che di norma indica
+ solo una preferenza, non un requisito assoluto.} e per poter risolvere
+questo tipo di problematiche nei nuovi kernel\footnote{le due \textit{system
+ call} per la gestione della \textit{CPU affinity} sono state introdotte
+ nel kernel 2.5.8, e le corrispondenti funzioni di sistema nella
+ \textsl{glibc} 2.3.} è stata introdotta l'opportuna infrastruttura ed una
+nuova \textit{system call} che permette di impostare su quali processori far
+eseguire un determinato processo attraverso una \textsl{maschera di
+ affinità}. La corrispondente funzione di sistema è
+\funcd{sched\_setaffinity} ed il suo prototipo è:
+
+\index{insieme~di~processori|(}
+
+\begin{funcproto}{
+\fhead{sched.h}
+\fdecl{int sched\_setaffinity(pid\_t pid, size\_t setsize,
+ cpu\_set\_t *mask)}
+\fdesc{Imposta la maschera di affinità di un processo.}
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+caso \var{errno} assumerà uno dei valori:
+\begin{errlist}
+\item[\errcode{EINVAL}] il valore di \param{mask} contiene riferimenti a
+ processori non esistenti nel sistema o a cui non è consentito l'accesso.
+\item[\errcode{EPERM}] il processo non ha i privilegi sufficienti per
+ eseguire l'operazione.
+\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+\end{errlist}
+ed inoltre anche \errval{EFAULT} nel suo significato generico.}
+\end{funcproto}
+
+Questa funzione e la corrispondente \func{sched\_getaffinity} hanno una storia
+abbastanza complessa, la sottostante \textit{system call} infatti prevede
+l'uso di due soli argomenti (per il pid e l'indicazione della maschera dei
+processori), che corrispondono al fatto che l'implementazione effettiva usa
+una semplice maschera binaria. Quando le funzioni vennero incluse nella
+\acr{glibc} assunsero invece un prototipo simile a quello mostrato però con il
+secondo argomento di tipo \ctyp{unsigned int}. A complicare la cosa si
+aggiunge il fatto che nella versione 2.3.3 della \acr{glibc} detto argomento
+venne stato eliminato, per poi essere ripristinato nella versione 2.3.4 nella
+forma attuale.\footnote{pertanto se la vostra pagina di manuale non è
+ aggiornata, o usate quella particolare versione della \acr{glibc}, potrete
+ trovare indicazioni diverse, il prototipo illustrato è quello riportato
+ nella versione corrente (maggio 2008) delle pagine di manuale e
+ corrispondente alla definizione presente in \headfile{sched.h}.}
+
+La funzione imposta, con l'uso del valore contenuto all'indirizzo
+\param{mask}, l'insieme dei processori sui quali deve essere eseguito il
+processo identificato tramite il valore passato in \param{pid}. Come in
+precedenza il valore nullo di \param{pid} indica il processo corrente. Per
+poter utilizzare questa funzione sono richiesti i privilegi di amministratore
+(è necessaria la capacità \const{CAP\_SYS\_NICE}) altrimenti essa fallirà con
+un errore di \errcode{EPERM}. Una volta impostata una maschera di affinità,
+questa viene ereditata attraverso una \func{fork}, in questo modo diventa
+possibile legare automaticamente un gruppo di processi ad un singolo
+processore.
+
+Nell'uso comune, almeno con i kernel successivi alla serie 2.6.x, l'uso di
+questa funzione non è necessario, in quanto è lo \textit{scheduler} stesso che
+provvede a mantenere al meglio l'affinità di processore. Esistono però
+esigenze particolari, ad esempio quando un processo (o un gruppo di processi)
+è utilizzato per un compito importante (ad esempio per applicazioni
+\textit{real-time} o la cui risposta è critica) e si vuole la massima
+velocità, e con questa interfaccia diventa possibile selezionare gruppi di
+processori utilizzabili in maniera esclusiva. Lo stesso dicasi quando
+l'accesso a certe risorse (memoria o periferiche) può avere un costo diverso a
+seconda del processore, come avviene nelle architetture NUMA
+(\textit{Non-Uniform Memory Access}).
+
+Infine se un gruppo di processi accede alle stesse risorse condivise (ad
+esempio una applicazione con più \textit{thread}) può avere senso usare lo
+stesso processore in modo da sfruttare meglio l'uso della sua cache; questo
+ovviamente riduce i benefici di un sistema multiprocessore nell'esecuzione
+contemporanea dei \textit{thread}, ma in certi casi (quando i \textit{thread}
+sono inerentemente serializzati nell'accesso ad una risorsa) possono esserci
+sufficienti vantaggi nell'evitare la perdita della cache da rendere
+conveniente l'uso dell'affinità di processore.
+
+Dato che il numero di processori può variare a seconda delle architetture, per
+semplificare l'uso dell'argomento \param{mask} la \acr{glibc} ha introdotto un
+apposito dato di tipo, \typed{cpu\_set\_t},\footnote{questa è una estensione
+ specifica della \acr{glibc}, da attivare definendo la macro
+ \macro{\_GNU\_SOURCE}, non esiste infatti una standardizzazione per questo
+ tipo di interfaccia e POSIX al momento non prevede nulla al riguardo.} che
+permette di identificare un insieme di processori. Il dato è normalmente una
+maschera binaria: nei casi più comuni potrebbe bastare un intero a 32 bit, in
+cui ogni bit corrisponde ad un processore, ma oggi esistono architetture in
+cui questo numero può non essere sufficiente, e per questo è stato creato
+questo tipo opaco e una interfaccia di gestione che permette di usare a basso
+livello un tipo di dato qualunque rendendosi indipendenti dal numero di bit e
+dalla loro disposizione. Per questo le funzioni richiedono anche che oltre
+all'insieme di processori si indichi anche la dimensione dello stesso con
+l'argomento \param{setsize}, per il quale, se non si usa l'allocazione
+dinamica che vedremo a breve, ed è in genere sufficiente passare il valore
+\code{sizeof(cpu\_set\_t)}.
+
+L'interfaccia di gestione degli insiemi di processori, oltre alla definizione
+del tipo \type{cpu\_set\_t}, prevede una serie di macro di preprocessore per
+la manipolazione degli stessi. Quelle di base, che consentono rispettivamente
+di svuotare un insieme, di aggiungere o togliere un processore o di verificare
+se esso è già presente in un insieme, sono le seguenti:
+
+{\centering
+\vspace{3pt}
+\begin{funcbox}{
+\fhead{sched.h}
+\fdecl{void \macrod{CPU\_ZERO}(cpu\_set\_t *set)}
+\fdesc{Inizializza un insieme di processori vuoto \param{set}.}
+\fdecl{void \macrod{CPU\_SET}(int cpu, cpu\_set\_t *set)}
+\fdesc{Inserisce il processore \param{cpu} nell'insieme di
+ processori \param{set}.}
+\fdecl{void \macrod{CPU\_CLR}(int cpu, cpu\_set\_t *set)}
+\fdesc{Rimuove il processore \param{cpu} nell'insieme di
+ processori \param{set}.}
+\fdecl{int \macrod{CPU\_ISSET}(int cpu, cpu\_set\_t *set)}
+\fdesc{Controlla se il processore \param{cpu} è nell'insieme di
+ processori \param{set}.}
+}
+\end{funcbox}}
+
+Queste macro che sono ispirate dalle analoghe usate per gli insiemi di
+\textit{file descriptor} (vedi sez.~\ref{sec:file_select}) e sono state
+introdotte con la versione 2.3.3 della \acr{glibc}. Tutte richiedono che si
+specifichi il numero di una CPU nell'argomento \param{cpu}, ed un insieme su
+cui operare. L'unica che ritorna un risultato è \macro{CPU\_ISSET}, che
+restituisce un intero da usare come valore logico (zero se la CPU non è
+presente, diverso da zero se è presente).
+
+\itindbeg{side~effects}
+Si tenga presente che trattandosi di macro l'argomento \param{cpu} può essere
+valutato più volte. Questo significa ad esempio che non si può usare al suo
+posto una funzione o un'altra macro, altrimenti queste verrebbero eseguite più
+volte, l'argomento cioè non deve avere \textsl{effetti collaterali} (in gergo
+ \textit{side effects}).\footnote{nel linguaggio C si
+ parla appunto di \textit{side effects} quando si usano istruzioni la cui
+ valutazione comporta effetti al di fuori dell'istruzione stessa, come il
+ caso indicato in cui si passa una funzione ad una macro che usa l'argomento
+ al suo interno più volte, o si scrivono espressioni come \code{a=a++} in cui
+ non è chiaro se prima avvenga l'incremento e poi l'assegnazione, ed il cui
+ risultato dipende dall'implementazione del compilatore.}
+\itindend{side~effects}
+
+
+Le CPU sono numerate da zero (che indica la prima disponibile) fino ad
+un numero massimo che dipende dalla architettura hardware. La costante
+\constd{CPU\_SETSIZE} indica il numero massimo di processori che possono far
+parte di un insieme (al momento vale sempre 1024), e costituisce un limite
+massimo al valore dell'argomento \param{cpu}.
+Dalla versione 2.6 della \acr{glibc} alle precedenti macro è stata aggiunta,
+per contare il numero di processori in un insieme, l'ulteriore:
+
+{\centering
+\vspace{3pt}
+\begin{funcbox}{
+\fhead{sched.h}
+\fdecl{int \macrod{CPU\_COUNT}(cpu\_set\_t *set)}
+\fdesc{Conta il numero di processori presenti nell'insieme \param{set}.}
+}
+\end{funcbox}}
+
+A partire dalla versione 2.7 della \acr{glibc} sono state introdotte altre
+macro che consentono ulteriori manipolazioni, in particolare si possono
+compiere delle operazioni logiche sugli insiemi di processori con:
+
+{\centering
+\vspace{3pt}
+\begin{funcbox}{
+\fhead{sched.h}
+\fdecl{void \macrod{CPU\_AND}(cpu\_set\_t *destset, cpu\_set\_t *srcset1, cpu\_set\_t *srcset2)}
+\fdesc{Esegue l'AND logico di due insiemi di processori.}
+\fdecl{void \macrod{CPU\_OR}(cpu\_set\_t *destset, cpu\_set\_t *srcset1, cpu\_set\_t *srcset2)}
+\fdesc{Esegue l'OR logico di due insiemi di processori.}
+\fdecl{void \macrod{CPU\_XOR}(cpu\_set\_t *destset, cpu\_set\_t *srcset1, cpu\_set\_t *srcset2)}
+\fdesc{Esegue lo XOR logico di due insiemi di processori.}
+\fdecl{int \macrod{CPU\_EQUAL}(cpu\_set\_t *set1, cpu\_set\_t *set2)}
+\fdesc{Verifica se due insiemi di processori sono uguali.}
+}
+\end{funcbox}}
+
+Le prime tre macro richiedono due insiemi di partenza, \param{srcset1}
+e \param{srcset2} e forniscono in un terzo insieme \param{destset} (che può
+essere anche lo stesso di uno dei precedenti) il risultato della rispettiva
+operazione logica sui contenuti degli stessi. In sostanza con \macro{CPU\_AND}
+si otterrà come risultato l'insieme che contiene le CPU presenti in entrambi
+gli insiemi di partenza, con \macro{CPU\_OR} l'insieme che contiene le CPU
+presenti in uno qualunque dei due insiemi di partenza, e con \macro{CPU\_XOR}
+l'insieme che contiene le CPU presenti presenti in uno solo dei due insiemi di
+partenza. Infine \macro{CPU\_EQUAL} confronta due insiemi ed è l'unica che
+restituisce un intero, da usare come valore logico che indica se sono
+identici o meno.
+
+Inoltre, sempre a partire dalla versione 2.7 della \acr{glibc}, è stata
+introdotta la possibilità di una allocazione dinamica degli insiemi di
+processori, per poterli avere di dimensioni corrispondenti al numero di CPU
+effettivamente in gioco, senza dover fare riferimento necessariamente alla
+precedente dimensione preimpostata di 1024. Per questo motivo sono state
+definite tre ulteriori macro, che consentono rispettivamente di allocare,
+disallocare ed ottenere la dimensione in byte di un insieme di processori:
+
+{\centering
+\vspace{3pt}
+\begin{funcbox}{
+\fhead{sched.h}
+\fdecl{cpu\_set\_t * \macrod{CPU\_ALLOC}(num\_cpus)}
+\fdesc{Alloca dinamicamente un insieme di processori di dimensione voluta.}
+\fdecl{void \macrod{CPU\_FREE}(cpu\_set\_t *set)}
+\fdesc{Disalloca un insieme di processori allocato dinamicamente.}
+\fdecl{size\_t \macrod{CPU\_ALLOC\_SIZE}(num\_cpus)}
+\fdesc{Ritorna la dimensione di un insieme di processori allocato dinamicamente.}
+}
+\end{funcbox}}
+
+La prima macro, \macro{CPU\_ALLOC}, restituisce il puntatore ad un insieme di
+processori in grado di contenere almeno \param{num\_cpus} che viene allocato
+dinamicamente. Ogni insieme così allocato dovrà essere disallocato con
+\macro{CPU\_FREE} passandogli un puntatore ottenuto da una precedente
+\macro{CPU\_ALLOC}. La terza macro, \macro{CPU\_ALLOC\_SIZE}, consente di
+ottenere la dimensione in byte di un insieme allocato dinamicamente che
+contenga \param{num\_cpus} processori.
+
+Dato che le dimensioni effettive possono essere diverse le macro di gestione e
+manipolazione che abbiamo trattato in precedenza non si applicano agli insiemi
+allocati dinamicamente, per i quali dovranno sono state definite altrettante
+macro equivalenti contraddistinte dal suffisso \texttt{\_S}, che effettuano le
+stesse operazioni, ma richiedono in più un argomento
+aggiuntivo \param{setsize} che deve essere assegnato al valore ottenuto con
+\macro{CPU\_ALLOC\_SIZE}. Questo stesso valore deve essere usato per l'omonimo
+argomento delle funzioni \func{sched\_setaffinity} o \func{sched\_getaffinity}
+quando si vuole usare per l'argomento che indica la maschera di affinità un
+insieme di processori allocato dinamicamente.
+
+\index{insieme~di~processori|)}
+
+A meno di non aver utilizzato \func{sched\_setaffinity}, in condizioni
+ordinarie la maschera di affinità di un processo è preimpostata dal sistema in
+modo che esso possa essere eseguito su qualunque processore. Se ne può
+comunque ottenere il valore corrente usando la funzione di sistema
+\funcd{sched\_getaffinity}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sched.h}
+\fdecl{int sched\_getaffinity (pid\_t pid, size\_t setsize,
+ cpu\_set\_t *mask)}
+\fdesc{Legge la maschera di affinità di un processo.}
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+caso \var{errno} assumerà uno dei valori:
+\begin{errlist}
+\item[\errcode{EINVAL}] \param{setsize} è più piccolo delle dimensioni
+ della maschera di affinità usata dal kernel.
+\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+\end{errlist}
+ed inoltre anche \errval{EFAULT} nel suo significato generico.}
+\end{funcproto}
+
+La funzione restituirà all'indirizzo specificato da \param{mask} il valore
+della maschera di affinità del processo indicato dall'argomento \param{pid}
+(al solito un valore nullo indica il processo corrente) così da poterla
+riutilizzare per una successiva reimpostazione.
+
+È chiaro che queste funzioni per la gestione dell'affinità hanno significato
+soltanto su un sistema multiprocessore, esse possono comunque essere
+utilizzate anche in un sistema con un processore singolo, nel qual caso però
+non avranno alcun risultato effettivo.
+
+\itindend{scheduler}
+\itindend{CPU~affinity}
+
+
+\subsection{Le priorità per le operazioni di I/O}
+\label{sec:io_priority}
+
+A lungo l'unica priorità usata per i processi è stata quella relativa
+all'assegnazione dell'uso del processore. Ma il processore non è l'unica
+risorsa che i processi devono contendersi, un'altra, altrettanto importante
+per le prestazioni, è quella dell'accesso a disco. Per questo motivo nello
+sviluppo del kernel sono stati introdotti diversi \textit{I/O scheduler} in
+grado di distribuire in maniera opportuna questa risorsa ai vari processi.
+
+Fino al kernel 2.6.17 era possibile soltanto differenziare le politiche
+generali di gestione, scegliendo di usare un diverso \textit{I/O scheduler}. A
+partire da questa versione, con l'introduzione dello \textit{scheduler} CFQ
+(\textit{Completely Fair Queuing}) è divenuto possibile, qualora si usi questo
+\textit{scheduler}, impostare anche delle diverse priorità di accesso per i
+singoli processi.\footnote{al momento (kernel 2.6.31), le priorità di I/O sono
+ disponibili soltanto per questo \textit{scheduler}.}
+
+La scelta di uno \textit{scheduler} di I/O si può fare in maniera generica per
+tutto il sistema all'avvio del kernel con il parametro di avvio
+\texttt{elevator},\footnote{per la trattazione dei parametri di avvio del
+ kernel si rimanda al solito alla sez.~5.3 di \cite{AGL}.} cui assegnare il
+nome dello \textit{scheduler}, ma se ne può anche indicare uno specifico per
+l'accesso al singolo disco scrivendo nel file
+\texttt{/sys/block/\textit{<dev>}/queue/scheduler} (dove
+\texttt{\textit{<dev>}} è il nome del dispositivo associato al disco).
+
+Gli \textit{scheduler} disponibili sono mostrati dal contenuto dello stesso
+file che riporta fra parentesi quadre quello attivo, il default in tutti i
+kernel recenti è proprio il \texttt{cfq},\footnote{nome con cui si indica
+ appunto lo \textit{scheduler} CFQ.} che supporta le priorità. Per i dettagli
+sulle caratteristiche specifiche degli altri \textit{scheduler}, la cui
+discussione attiene a problematiche di ambito sistemistico, si consulti la
+documentazione nella directory \texttt{Documentation/block/} dei sorgenti del
+kernel.
+
+Una volta che si sia impostato lo \textit{scheduler} CFQ ci sono due
+specifiche \textit{system call}, specifiche di Linux, che consentono di
+leggere ed impostare le priorità di I/O.\footnote{se usate in corrispondenza
+ ad uno \textit{scheduler} diverso il loro utilizzo non avrà alcun effetto.}
+Dato che non esiste una interfaccia diretta nella \acr{glibc} per queste due
+funzioni\footnote{almeno al momento della scrittura di questa sezione, con la
+ versione 2.11 della \acr{glibc}.} occorrerà invocarle tramite la funzione
+\func{syscall} (come illustrato in sez.~\ref{sec:proc_syscall}). Le due
+\textit{system call} sono \funcd{ioprio\_get} ed \funcd{ioprio\_set}; i
+rispettivi prototipi sono:
+
+\begin{funcproto}{
+\fhead{linux/ioprio.h}
+\fdecl{int ioprio\_get(int which, int who)}
+\fdesc{Legge la priorità di I/O di un processo.}
+\fdecl{int ioprio\_set(int which, int who, int ioprio)}
+\fdesc{Imposta la priorità di I/O di un processo.}
+}
+{Le funzioni ritornano rispettivamente un intero positivo o 0 in caso di
+ successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei
+ valori:
+\begin{errlist}
+\item[\errcode{EINVAL}] i valori di \param{which} o di \param{ioprio} non
+ sono validi.
+\item[\errcode{EPERM}] non si hanno i privilegi per eseguire
+ l'impostazione (solo per \func{ioprio\_set}).
+\item[\errcode{ESRCH}] non esiste un processo corrispondente alle indicazioni.
+\end{errlist}}
+\end{funcproto}
+
+Le funzioni leggono o impostano la priorità di I/O sulla base dell'indicazione
+dei due argomenti \param{which} e \param{who} che hanno lo stesso significato
+già visto per gli omonimi argomenti di \func{getpriority} e
+\func{setpriority}. Anche in questo caso si deve specificare il valore
+di \param{which} tramite le opportune costanti riportate in
+tab.~\ref{tab:ioprio_args} che consentono di indicare un singolo processo, i
+processi di un \textit{process group} (tratteremo questo argomento in
+sez.~\ref{sec:sess_proc_group}) o tutti i processi di un utente.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|c|c|l|}
+ \hline
+ \param{which} & \param{who} & \textbf{Significato} \\
+ \hline
+ \hline
+ \constd{IPRIO\_WHO\_PROCESS} & \type{pid\_t} & processo\\
+ \constd{IPRIO\_WHO\_PRGR} & \type{pid\_t} & \textit{process group}\\
+ \constd{IPRIO\_WHO\_USER} & \type{uid\_t} & utente\\
+ \hline
+ \end{tabular}
+ \caption{Legenda del valore dell'argomento \param{which} e del tipo
+ dell'argomento \param{who} delle funzioni \func{ioprio\_get} e
+ \func{ioprio\_set} per le tre possibili scelte.}
+ \label{tab:ioprio_args}
+\end{table}