viene utilizzato solo quando necessario. Quanto detto in precedenza vale
allora soltanto per i kernel fino al 2.4; per mantenere la portabilità è però
opportuno non fare affidamento su questo comportamento, che non si riscontra
-in altri Unix e nelle versioni del kernel precendenti a quella indicata.
+in altri Unix e nelle versioni del kernel precedenti a quella indicata.
Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
processi completamente separati, le modifiche delle variabili nei processi
\item i segmenti di memoria condivisa agganciati al processo (vedi
sez.~\ref{sec:ipc_sysv_shm});
\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit});
-\item le priorità real-time e le affinità di processore (vedi
+\item il valori di \textit{nice}, le priorità real-time e le affinità di
+ processore (vedi sez.~\ref{sec:proc_sched_stand},
sez.~\ref{sec:proc_real_time} e sez.\ref{sec:proc_sched_multiprocess});
\item le variabili di ambiente (vedi sez.~\ref{sec:proc_environ}).
\end{itemize*}
\subsection{Il meccanismo di \textit{scheduling} standard}
\label{sec:proc_sched_stand}
-A meno che non si abbiano esigenze specifiche, l'unico meccanismo di
+A meno che non si abbiano esigenze specifiche,\footnote{per alcune delle quali
+ sono state introdotte delle varianti 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 i processi ordinari hanno tutti
ed è stata anche introdotta la possibilità di usare diversi algoritmi,
selezionabili sia in fase di compilazione, che, nelle versioni più recenti,
all'avvio (addirittura è stato ideato un sistema modulare che permette di
- cambiare lo scheduler al volo, che comunque non è incluso nel kernel
- ufficiale).} ma a grandi linee si può dire che ad ogni processo è assegnata
-una \textit{time-slice}, cioè un intervallo di tempo (letteralmente una fetta)
-per il quale, a meno di eventi esterni, esso viene eseguito senza essere
-interrotto. Il valore della \textit{time-slice} è stabilito dalla sua
-cosiddetta \textit{nice} (o \textit{niceness}) del processo. Questo è un
-valore, che di default è nullo, e che oltre a essere associato alla lunghezza
-della \textit{timesllce} viene anche sommato alla priorità dinamica di ciascun
-processo. Questa viene calcolata dallo scheduler e viene \textsl{diminuita}
-tutte le volte che un processo è in stato \textbf{Runnable} ma non viene posto
-in esecuzione. Lo scheduler infatti mette sempre in esecuzione, fra tutti i
-processi in stato \textbf{Runnable}, quello che ha la priorità dinamica più
-bassa.\footnote{in realtà il calcolo della priorità dinamica e la scelta di
- quale processo mettere in esecuzione avviene con un algoritmo più
- complicato, (per una buona trattazione vedi \cite{XXX}), ad esempio nei
- sistemi multiprocessore viene favorito un processo eseguito sulla stessa
- CPU.}
-
-La priorità di un processo è così controllata attraverso il valore di
-\var{nice}, che stabilisce la durata della \textit{time-slice} (un valore di
-nice più alto corrisponde ad una \textit{time-sl}, ed ovviamente
-più questa è ampia e più lungo sarà il tempo che esso resta in esecuzione in
-esecuzione. Ma per il meccanismo appana descritto, andando a sommarsi alla
-priorità dianamica, essa tenderà anche a sfavorire (o fa
-
-per il
-meccanismo appena descritto infatti un valore più lungo assicura una maggiore
-attribuzione di CPU. L'origine del nome di questo parametro sta nel fatto che
-generalmente questo viene 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 \funcd{nice}, il cui prototipo è:
+ cambiare lo scheduler a sistema attivo).} ma a grandi linee si può dire che
+ad ogni processo è assegnata una \textit{time-slice}, cioè un intervallo di
+tempo (letteralmente una fetta) per il quale, a meno di eventi esterni, esso
+viene eseguito senza essere interrotto. Inoltre la priorità dinamica viene
+calcolata dallo scheduler a partire da un valore iniziale che viene
+\textsl{diminuito} tutte le volte che un processo è in stato \textbf{Runnable}
+ma non viene posto in esecuzione.\footnote{in realtà il calcolo della priorità
+ dinamica e la conseguente scelta di quale processo mettere in esecuzione
+ avviene con un algoritmo molto più complicato, che tiene conto anche della
+ \textsl{interattività} del processo, utilizzando diversi fattori, questa è
+ una brutale semplificazione per rendere l'idea del funzionamento, per una
+ trattazione più dettagliata, anche se non aggiornatissima, dei meccanismi di
+ funzionamento dello scheduler si legga il quarto capitolo di
+ \cite{LinKernDev}.} Lo scheduler infatti mette sempre in esecuzione, fra
+tutti i processi in stato \textbf{Runnable}, quello che ha il valore di
+priorità dinamica più basso.\footnote{con le priorità dinamiche il significato
+ del valore numerico ad esse associato è infatti invertito, un valore più
+ basso significa una priorità maggiore.} Il fatto che questo valore venga
+diminuito quando un processo non viene posto in esecuzione pur essendo pronto,
+significa che la priorità dei processi che non ottengono l'uso del processore
+viene progressivamente incrementata, così che anche questi alla fine hanno la
+possibilità di essere eseguiti.
+
+Sia la dimensione della \textit{time-slice} che il valore di partenza della
+priorità dinamica sono determinate dalla cosiddetta \textit{nice} (o
+\textit{niceness}) del processo.\footnote{questa è una delle tante proprietà
+ che ciascun processo si porta dietro, essa viene ereditata dai processi
+ figli e mantenuta attraverso una \func{exec}; fino alla serie 2.4 essa era
+ mantenuta nell'omonimo campo \texttt{nice} della \texttt{task\_struct}, con
+ la riscrittura dello scheduler eseguita nel 2.6 viene mantenuta nel campo
+ \texttt{static\_prio} come per le priorità statiche.} L'origine del nome di
+questo parametro sta nel fatto che generalmente questo viene usato per
+\textsl{diminuire} la priorità di un processo, come misura di cortesia nei
+confronti degli altri. I processi infatti vengono creati dal sistema con un
+valore di \var{nice} nullo e nessuno è privilegiato rispetto agli altri;
+specificando un valore positivo si avrà una \textit{time-slice} più breve ed
+un valore di priorità dinamica iniziale più alto, mentre un valore negativo
+darà una \textit{time-slice} più lunga ed un valore di priorità dinamica
+iniziale più basso.
+
+Esistono diverse funzioni che consentono di modificare la \textit{niceness} di
+un processo; la più semplice è funzione \funcd{nice}, che opera sul processo
+corrente, il suo prototipo è:
\begin{prototype}{unistd.h}
{int nice(int inc)}
Aumenta il valore di \var{nice} per il processo corrente.
di successo e -1 in caso di errore, nel qual caso \var{errno} può assumere
i valori:
\begin{errlist}
- \item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha
- specificato un valore di \param{inc} negativo.
+ \item[\errcode{EPERM}] non si ha il permesso di specificare 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 \const{PRIO\_MIN} e
-\const{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.
+L'argomento \param{inc} indica l'incremento da effettuare rispetto al valore
+di \var{nice} corrente: quest'ultimo può assumere valori compresi fra
+\const{PRIO\_MIN} e \const{PRIO\_MAX}; nel caso di Linux sono fra $-20$ e
+$19$,\footnote{in realtà l'intervallo varia a seconda delle versioni di
+ kernel, ed è questo a partire dal kernel 1.3.43, anche se oggi si può avere
+ anche l'intervallo fra $-20$ 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à, valori negativi
+comportano invece un aumento della priorità. Con i kernel precedenti il
+2.6.12 solo l'amministratore\footnote{o un processo con la
+ \itindex{capabilities} \textit{capability} \const{CAP\_SYS\_NICE}, vedi
+ sez.~\ref{sec:proc_capabilities}.} può specificare valori negativi
+di \param{inc} che permettono di aumentare la priorità di un processo, a
+partire da questa versione è consentito anche agli utenti normali alzare
+(entro certi limiti, che vedremo più avanti) la priorità dei propri processi.
Gli standard SUSv2 e POSIX.1 prevedono che la funzione ritorni il nuovo valore
di \var{nice} del processo; tuttavia la system call di Linux non segue questa
-convenzione e restituisce sempre 0 in caso di successo, questo perché $-1$ è
-un valore di \var{nice} legittimo e questo comporta una confusione con una
-eventuale condizione di errore.
-
+convenzione e restituisce sempre 0 in caso di successo e $-1$ in caso di
+errore; questo perché $-1$ è un valore di \var{nice} legittimo e questo
+comporta una confusione con una eventuale condizione di errore. La system call
+originaria inoltre non consente, se non dotati di adeguati privilegi, di
+diminuire un valore di \var{nice} precedentemente innalzato.
+
Fino alle \acr{glibc} 2.2.4 la funzione di libreria riportava direttamente il
-valore ottenuto dalla system call, violando lo standard, per cui per ottenere
-il nuovo valore occorreva una successiva chiamata alla funzione
+risultato dalla system call, violando lo standard, per cui per ottenere il
+nuovo valore occorreva una successiva chiamata alla funzione
\func{getpriority}. A partire dalla \acr{glibc} 2.2.4 \func{nice} è stata
-reimplementata come funzione di libreria, e restituisce il valore di
-\var{nice} come richiesto dallo standard.\footnote{questo viene fatto
- chiamando al suo interno \func{getpriority}, ed è questo il motivo delle due
- possibilità per i valori di ritorno citati nella descrizione del prototipo.}
-In questo caso l'unico modo per rilevare in maniera affidabile una condizione
-di errore è quello di azzerare \var{errno} prima della chiamata della funzione
-e verificarne il valore quando \func{nice} restituisce $-1$.
-
-
-Per leggere il valore di nice di un processo occorre usare la funzione
-\funcd{getpriority}, derivata da BSD; il suo prototipo è:
+reimplementata e non viene più chiamata la omonima system call, con questa
+versione viene restituito come valore di ritorno il valore di \var{nice}, come
+richiesto dallo standard.\footnote{questo viene fatto chiamando al suo interno
+ \func{setpriority}, che tratteremo a breve.} In questo caso l'unico modo
+per rilevare in maniera affidabile una condizione di errore è quello di
+azzerare \var{errno} prima della chiamata della funzione e verificarne il
+valore quando \func{nice} restituisce $-1$.
+
+Per leggere il valore di \textit{nice} di un processo occorre usare la
+funzione \funcd{getpriority}, derivata da BSD; il suo prototipo è:
\begin{prototype}{sys/resource.h}
{int getpriority(int which, int who)}
\item[\errcode{ESRCH}] non c'è nessun processo che corrisponda ai valori di
\param{which} e \param{who}.
\item[\errcode{EINVAL}] il valore di \param{which} non è valido.
+ \item[\errcode{EACCES}] si è richiesto un aumento di priorità senza avere
+ sufficienti privilegi.
\item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha
- specificato un valore di \param{inc} negativo.
- \item[\errcode{EACCES}] 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 imposta 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 l'user-ID reale o effettivo 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'user-ID effettivo.
-
+tutti i processi indicati dagli argomenti \param{which} e \param{who}. In
+questo caso come valore di \param{prio} deve essere specificato il valore di
+\textit{nice} da assegnare, e non un incremento (positivo o negativo) come nel
+caso di \func{nice}. La funzione restituisce il valore di \textit{nice}
+assegnato in caso di successo e $-1$ in caso di errore, e come per \func{nice}
+anche in questo caso per rilevare un errore occorre sempre porre a zero
+\var{errno} prima della chiamata della funzione, essendo $-1$ un valore di
+\textit{nice} valido.
+
+Si tenga presente che solo l'amministratore\footnote{o più precisamente un
+ processo con la \itindex{capabilities} \textit{capability}
+ \const{CAP\_SYS\_NICE}, vedi sez.~\ref{sec:proc_capabilities}.} ha la
+possibilità di modificare arbitrariamente le priorità di qualunque
+processo. Un utente normale infatti può modificare solo la priorità dei suoi
+processi ed in genere soltanto diminuirla. Fino alla versione di kernel
+2.6.12 Linux ha seguito le specifiche dello standard SUSv3, e come per tutti i
+sistemi derivati da SysV veniva richiesto che l'user-ID reale o quello
+effettivo del processo chiamante corrispondessero all'user-ID reale (e solo a
+quello) del processo di cui si intendeva cambiare la priorità. A partire dalla
+versione 2.6.12 è stata adottata la semantica in uso presso i sistemi derivati
+da BSD (SunOS, Ultrix, *BSD), in cui la corrispondenza può essere anche con
+l'user-ID effettivo.
+
+Sempre a partire dal kernel 2.6.12 è divenuto possibile anche per gli utenti
+ordinari poter aumentare la priorità dei propri processi specificando un
+valore di \param{prio} negativo. Questa operazione non è possibile però in
+maniera indiscriminata, ed in particolare può essere effettuata solo
+nell'intervallo consentito dal valore del limite \const{RLIMIT\_NICE}
+(torneremo su questo in sez.~\ref{sec:sys_resource_limit}).
\subsection{Il meccanismo di \textit{scheduling real-time}}
sez.~\ref{sec:proc_mem_lock}), il primo non è superabile e può comportare
ritardi non prevedibili riguardo ai tempi di esecuzione di qualunque processo.
-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.
+Nonostante questo, ed in particolare con una serie di miglioramenti che sono
+stati introdotti nello sviluppo del kernel,\footnote{in particolare a partire
+ dalla versione 2.6.18 sono stati inserite nel kernel una serie di modifiche
+ che consentono di avvicinarsi sempre di più ad un vero e proprio sistema
+ \textit{real-time} estendendo il concetto di \textit{preemption} alle
+ operazioni dello stesso kernel; esistono vari livelli a cui questo può
+ essere fatto, ottenibili attivando in fase di compilazione una fra le
+ opzioni \texttt{CONFIG\_PREEMPT\_NONE}, \texttt{CONFIG\_PREEMPT\_VOLUNTARY}
+ e \texttt{CONFIG\_PREEMPT\_DESKTOP}.} si può arrivare ad una ottima
+approssimazione di sistema real-time usando le priorità assolute; occorre
+farlo però 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à
\item[\textsf{RR}] \textit{Round Robin}. Il comportamento è del tutto analogo
a quello precedente, con la sola differenza che ciascun processo viene
eseguito al massimo per un certo periodo di tempo (la cosiddetta
- \textit{time slice}) dopo di che viene automaticamente posto in fondo alla
+ \textit{time-slice}) dopo di che viene automaticamente posto in fondo alla
coda dei processi con la stessa priorità. In questo modo si ha comunque una
esecuzione a turno di tutti i processi, da cui il nome della politica. Solo
- i processi con la stessa priorità ed in stato \textit{runnable} entrano nel
+ i processi con la stessa priorità ed in stato \textbf{Runnable} entrano nel
\textsl{girotondo}.
\end{basedescript}
-La funzione per impostare le politiche di scheduling (sia real-time che
-ordinarie) ed i relativi parametri è \funcd{sched\_setscheduler}; il suo
-prototipo è:
+Lo standard POSIX.1-2001 prevede una funzione che consenta sia di modificare
+le politiche di scheduling, passando da real-time a ordinarie o viceversa, che
+di specificare, in caso di politiche real-time, la eventuale priorità statica;
+la funzione è \funcd{sched\_setscheduler} ed il suo prototipo è:
\begin{prototype}{sched.h}
{int sched\_setscheduler(pid\_t pid, int policy, const struct sched\_param *p)}
Imposta priorità e politica di scheduling.
- \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso
+ \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[\errcode{ESRCH}] il processo \param{pid} non esiste.
\end{prototype}
La funzione esegue l'impostazione per il processo specificato dall'argomento
-\param{pid}; un valore nullo esegue l'impostazione per il processo corrente.
-La politica di scheduling è specificata dall'argomento \param{policy} i cui
-possibili valori sono riportati in tab.~\ref{tab:proc_sched_policy}; un valore
-negativo per \param{policy} mantiene la politica di scheduling corrente. Solo
-un processo con i privilegi di amministratore\footnote{più precisamente con la
- \itindex{capabilities} \textit{capability} \const{CAP\_SYS\_NICE}, vedi
- sez.~\ref{sec:proc_capabilities}.} può impostare priorità assolute diverse
-da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}.
+\param{pid}; un valore nullo di questo argomento esegue l'impostazione per il
+processo corrente. La politica di scheduling è specificata
+dall'argomento \param{policy} i cui possibili valori sono riportati in
+tab.~\ref{tab:proc_sched_policy}; la parte alta della tabella indica le
+politiche real-time, quella bassa le politiche ordinarie. Un valore negativo
+per \param{policy} mantiene la politica di scheduling corrente.
\begin{table}[htb]
\centering
\const{SCHED\_FIFO} & Scheduling real-time con politica \textit{FIFO}. \\
\const{SCHED\_RR} & Scheduling real-time con politica \textit{Round
Robin}. \\
+ \hline
\const{SCHED\_OTHER}& Scheduling ordinario.\\
\const{SCHED\_BATCH}& Scheduling ordinario con l'assunzione ulteriore di
lavoro \textit{CPU intensive}.\footnotemark\\
- \const{SCHED\_IDLE} & Scheduling di priorità estremamente bassa.\\
+ \const{SCHED\_IDLE} & Scheduling di priorità estremamente
+ bassa.\footnotemark\\
\hline
\end{tabular}
\caption{Valori dell'argomento \param{policy} per la funzione
\label{tab:proc_sched_policy}
\end{table}
-\footnotetext{introdotto con il kernel 2.6.16.}
-
-Il valore della priorità è passato attraverso la struttura
-\struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui
-solo campo attualmente definito è \var{sched\_priority}, che nel caso delle
-priorità assolute deve essere specificato nell'intervallo fra un valore
-massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99; il valore
-nullo è legale, ma indica i processi normali.
+\footnotetext[41]{introdotto con il kernel 2.6.16.}
+\footnotetext{introdotto con il kernel 2.6.23.}
+
+Con le versioni più recenti del kernel sono state introdotte anche delle
+varianti sulla politica di scheduling tradizionale per alcuni carichi di
+lavoro specifici, queste due nuove politiche sono specifiche di Linux e non
+devono essere usate se si vogliono scrivere programmi portabili.
+
+La politica \const{SCHED\_BATCH} è una variante della politica ordinaria con
+la sola differenza che i processi ad essa soggetti non ottengono, nel calcolo
+delle priorità dinamiche fatto dallo scheduler, il cosiddetto bonus di
+interattività che mira a favorire i processi che si svegliano dallo stato di
+\textbf{Sleep}.\footnote{cosa che accade con grande frequenza per i processi
+ interattivi, dato che essi sono per la maggior parte del tempo in attesa di
+ dati in ingresso da parte dell'utente.} La si usa pertanto, come indica il
+nome, per processi che usano molta CPU (come programmi di calcolo) che in
+questo modo sono leggermente sfavoriti rispetto ai processi interattivi che
+devono rispondere a dei dati in ingresso, pur non perdendo il loro valore di
+\textit{nice}.
+
+La politica \const{SCHED\_IDLE} invece è una politica dedicata ai processi che
+si desidera siano eseguiti con la più bassa priorità possibile, ancora più
+bassa di un processo con il minimo valore di \textit{nice}. In sostanza la si
+può utilizzare per processi che devono essere eseguiti se non c'è niente altro
+da fare. Va comunque sottolineato che anche un processo \const{SCHED\_IDLE}
+avrà comunque una sua possibilità di utilizzo della CPU, sia pure in
+percentuale molto bassa.
+
+Qualora si sia richiesta una politica real-time il valore della priorità
+statica viene impostato attraverso la struttura \struct{sched\_param},
+riportata in fig.~\ref{fig:sig_sched_param}, il cui solo campo attualmente
+definito è \var{sched\_priority}. Il campo deve contenere il valore della
+priorità statica da assegnare al processo; lo standard prevede che questo
+debba essere assegnato all'interno di un intervallo fra un massimo ed un
+minimo che nel caso di Linux sono rispettivamente 1 e 99.
\begin{figure}[!bht]
\footnotesize \centering
\label{fig:sig_sched_param}
\end{figure}
-Si tenga presente che quando si imposta una politica di scheduling real-time
-per un processo (o se ne cambia la priorità con \func{sched\_setparam}) questo
-viene messo in cima alla lista dei processi con la stessa priorità; questo
-comporta che verrà eseguito subito, interrompendo eventuali altri processi con
-la stessa priorità in quel momento in esecuzione.
+I processi con politica di scheduling ordinaria devono sempre specificare un
+valore nullo di \var{sched\_priority} altrimenti si avrà un errore
+\errcode{EINVAL}, questo valore infatti non ha niente a che vedere con la
+priorità dinamica determinata dal valore di \textit{nice}, che deve essere
+impostato con le funzioni viste in precedenza.
Lo standard POSIX.1b prevede comunque che i due valori della massima e minima
priorità statica possano essere ottenuti, per ciascuna delle politiche di
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:
+ e $-1$ in caso di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
\item[\errcode{EINVAL}] il valore di \param{policy} non è valido.
\end{errlist}}
\end{functions}
-
-I processi con politica di scheduling \const{SCHED\_OTHER} devono specificare
-un valore nullo (altrimenti si avrà un errore \errcode{EINVAL}), questo valore
-infatti non ha niente a che vedere con la priorità dinamica determinata dal
-valore di \var{nice}, che deve essere impostato con le funzioni viste in
-precedenza.
+Si tenga presente che quando si imposta una politica di scheduling real-time
+per un processo o se ne cambia la priorità statica questo viene messo in cima
+alla lista dei processi con la stessa priorità; questo comporta che verrà
+eseguito subito, interrompendo eventuali altri processi con la stessa priorità
+in quel momento in esecuzione.
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
+stato \textbf{Runnable} viene sempre inserito in coda alla lista. Se la
politica scelta è \const{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}
+volontariamente la CPU (in tal caso, tornando nello stato \textbf{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.
-Se si intende operare solo sulla priorità assoluta di un processo si possono
-usare le funzioni \funcd{sched\_setparam} e \funcd{sched\_getparam}, i cui
+Solo un processo con i privilegi di amministratore\footnote{più precisamente
+ con la \itindex{capabilities} 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'user-ID effettivo del
+processo chiamante corrisponda all'user-ID reale o effettivo del processo
+indicato con \param{pid}.
+
+Fino al kernel 2.6.12 gli utenti normali non potevano impostare politiche
+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 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 scheduling indipendentemente dal valore di
+\const{RLIMIT\_RTPRIO}. Inoltre, in caso di processo già sottoposto ad una
+politica 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 \funcd{sched\_setparam} e \funcd{sched\_getparam} che
+consentono rispettivamente di impostarne e leggerne il valore, i loro
prototipi sono:
\begin{functions}
\headdecl{sched.h}
- \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)}
- Imposta la priorità assoluta del processo \param{pid}.
+ \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *param)}
+ Imposta la priorità statica del processo \param{pid}.
- \funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)}
- Legge la priorità assoluta del processo \param{pid}.
+ \funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *param)}
+ Legge la priorità statica 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:
+ \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ in
+ caso di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
- \item[\errcode{EINVAL}] il valore di \param{p} non ha senso per la
- politica scelta.
- \item[\errcode{EPERM}] il processo non ha i privilegi sufficienti per
- eseguire l'operazione.
+ \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.
\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 \file{sched.h}.
-
-Si tenga presente che per eseguire la funzione il processo chiamante deve
-avere un user-ID effettivo uguale all'user-ID reale o a quello effettivo del
-processo di cui vuole cambiare la priorità, oppure deve avere i privilegi di
-amministratore (con la capacità \const{CAP\_SYS\_NICE}).
-
-La priorità assoluta può essere riletta indietro dalla funzione
-\funcd{sched\_getscheduler}, il cui prototipo è:
+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 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
+\macro{\_POSIX\_PRIORITY\_SCHEDULING} che è definita nell'header
+\file{sched.h}.
+
+Se invece si vuole sapere quale è politica di scheduling di un processo si può
+usare la funzione \funcd{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:
+ e $-1$ in caso di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
- \item[\errcode{EINVAL}] il valore di \param{pid} è negativo.
- \end{errlist}}
+ \item[\errcode{EPERM}] non si hanno privilegi sufficienti per eseguire
+ l'operazione.
+ \end{errlist}}
\end{prototype}
-La funzione restituisce il valore (secondo quanto elencato in
-tab.~\ref{tab:proc_sched_policy}) della politica di scheduling per il processo
-specificato; se \param{pid} è nullo viene restituito quello del processo
-chiamante.
+La funzione restituisce il valore, secondo quanto elencato in
+tab.~\ref{tab:proc_sched_policy}, della politica di scheduling per il processo
+specificato; se l'argomento \param{pid} è nullo viene restituito il valore
+relativo al processo chiamante.
L'ultima funzione 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};
+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}.
+ \param{tp} la durata della \textit{time-slice} per il processo \param{pid}.
\bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
nel qual caso \var{errno} può assumere i valori:
questa funzione ritorna sempre un valore di 150 millisecondi, e non importa
specificare il PID di un processo reale.
-Come accennato ogni processo che usa lo scheduling real-time può rilasciare
-volontariamente la CPU; questo viene fatto attraverso la funzione
-\funcd{sched\_yield}, il cui prototipo è:
+Come accennato ogni processo può rilasciare volontariamente la CPU in modo da
+consentire agli altri processi di essere eseguiti; la funzione che consente di
+fare tutto ciò è \funcd{sched\_yield}, il cui prototipo è:
\begin{prototype}{sched.h}
{int sched\_yield(void)}
nel qual caso \var{errno} viene impostata opportunamente.}
\end{prototype}
-La funzione fa sì 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.
+Questa funzione ha un utilizzo effettivo soltanto quando si usa lo scheduling
+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 in modalità \textit{fifo}, per permettere
+l'esecuzione degli altri processi con pari priorità quando la sezione più
+urgente è finita.
% TODO: con il 2.6.23 il comportamento è stato leggermente modificato ed è
% stato introdotto /proc/sys/kernel/sched_compat_yield da mettere a 1 per aver
% LocalWords: parent kernel init pstree keventd kswapd table struct linux call
% LocalWords: nell'header scheduler system interrupt timer HZ asm Hertz clock
% LocalWords: l'alpha tick fork wait waitpid exit exec image glibc int pgid ps
-% LocalWords: sid thread Ingo Molnar ppid getpid getppid sys unistd LD
+% LocalWords: sid thread Ingo Molnar ppid getpid getppid sys unistd LD threads
% LocalWords: void ForkTest tempnam pathname sibling cap errno EAGAIN ENOMEM
% LocalWords: stack read only copy write tab client spawn forktest sleep PATH
% LocalWords: source LIBRARY scheduling race condition printf descriptor dup
% LocalWords: waitid NOCLDSTOP ENOCHLD WIFCONTINUED ifdef endif idtype siginfo
% LocalWords: infop ALL WEXITED WSTOPPED WNOWAIT signo CLD EXITED KILLED page
% LocalWords: CONTINUED sources forking Spawned successfully executing exiting
+% LocalWords: next cat for COMMAND pts bash defunct TRAPPED DUMPED Killable PR
+% LocalWords: SIGKILL static RLIMIT preemption PREEMPT VOLUNTARY IDLE
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
-% LocalWords: next cat for COMMAND pts bash defunct