da un numero identificativo unico, il \textit{process id} o \acr{pid};
quest'ultimo è un tipo di dato standard, il \type{pid\_t} che in genere è un
intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato è
-\type{int}).
+\ctyp{int}).
Il \acr{pid} viene assegnato in forma progressiva ogni volta che un nuovo
processo viene creato, fino ad un limite che, essendo il \acr{pid} un numero
\item la directory di lavoro e la directory radice (vedi
\secref{sec:file_work_dir} e \secref{sec:file_chroot}).
\item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
-\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigpending}) e le
+\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}) e le
azioni installate (vedi \secref{sec:sig_gen_beha}).
\item i segmenti di memoria condivisa agganciati al processo (vedi
\secref{sec:ipc_xxx}).
analizzare lo stato di uscita. Esse sono definite sempre in
\file{<sys/wait.h>} ed elencate in \tabref{tab:proc_status_macro} (si tenga
presente che queste macro prendono come parametro la variabile di tipo
-\type{int} puntata da \var{status}).
+\ctyp{int} puntata da \var{status}).
Si tenga conto che nel caso di conclusione anomala il valore restituito da
\macro{WTERMSIG} può essere confrontato con le costanti definite in
\secref{sec:file_umask}) ed i \textit{lock} sui file (vedi
\secref{sec:file_locking}).
\item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
- \secref{sec:sig_sigpending}).
+ \secref{sec:sig_sigmask}).
\item i limiti sulle risorse (vedi \secref{sec:sys_limits}).
\item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
\var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:xxx_xxx}).
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}; un valore più
-lungo infatti assicura una maggiore attribuzione di CPU. L'origine di questo
-parametro sta nel fatto che in genere esso viene generalmente usato come per
-diminuire la priorità di un processo, come termine di cortesia (da cui il
-nome) nei confronti degli altri.
+\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; il valore può essere modificato
-solo attraverso la funzione \func{nice}, il cui prototipo è:
+\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 utente normale ha specificato un valore di
- \param{inc} negativo.
+ \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
+\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à. Solo l'amministratore può specificare valori negativi che permettono
-di aumentare la priorità di un processo.
-
+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, per leggere il nuovo valore di occorre invece usare la
+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 la priorità per l'insieme dei processi specificati.
+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{ESRCH}] il valore di \param{which} non è valido.
+ \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}
-Per settare le
+Come spiegato in \secref{sec:proc_sched} lo standard POSIX.1b ha introdotto le
+priorità assolute per permettere la gestione di processi real-time. In realtà
+nel caso di Linux non si tratta di un vero hard real-time, in quanto in
+presenza di eventuali interrupt il kernel interrompe l'esecuzione di un
+processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si
+ siano installate le patch di RTLinux o RTAI, con i quali è possibile
+ ottenere un sistema effettivamente hard real-time. In tal caso infatti gli
+ interrupt vengono intercettati dall'interfaccia real-time, e gestiti
+ direttamente qualora ci sia la necessità di avere un processo con priorità
+ più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
+page fault si possono avere ritardi non previsti. Se l'ultimo problema può
+essere aggirato attraverso l'uso delle funzioni di controllo della memoria
+virtuale (vedi \secref{sec:proc_mem_lock}), il primo non è superabile e può
+comportare ritardi non prevedibili riguardo ai tempi di esecuzione di
+qualunque processo.
+
+In ogni caso occorre usare le priorità assolute con molta attenzione: se si dà
+ad un processo una priorità assoluta e questo finisce in un loop infinito,
+nessun altro processo potrà essere eseguito, ed esso sarà mantenuto in
+esecuzione permanentemente assorbendo tutta la CPU e senza nessuna possibilità
+di riottenere l'accesso al sistema. Per questo motivo è sempre opportuno,
+quando si lavora con processi che usano priorità assolute, tenere attiva una
+shell cui si sia assegnata la massima priorità assoluta, in modo da poter
+essere comunque in grado di rientrare nel sistema.
+
+Quando c'è un processo con priorità assoluta lo scheduler lo metterà in
+esecuzione prima di ogni processo normale. In caso di più processi sarà
+eseguito per primo quello con priorità assoluta più alta. Quando ci sono più
+processi con la stessa priorità assoluta questi 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}
-\footnote{a meno che non si siano installate le patch di RTLinux o RTAI, con i
- quali è possibile ottenere un sistema effettivamente hard real-time.}
-in realtà non si tratta di un vero hard real-time, in quanto
- la presenza di eventuali interrupt o di page fault può sempre interrompere
- l'esecuzione di un processo, a meno di non installare le estensioni di
- RTLinux o RTAI, il normale kernel non è real-time.
+I processi con politica di scheduling \macro{SCHED\_OTHER} devono specificare
+un valore nullo (altrimenti si avrà un errore \macro{EINVAL}), questo valore
+infatti non ha niente a che vedere con la priorità dinamica determinata dal
+valore di \var{nice}, che deve essere settato con le funzioni viste in
+precedenza.
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct sched_param {
+ int sched_priority;
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \var{sched\_param}.}
+ \label{fig:sig_sched_param}
+\end{figure}
+Il kernel mantiene i processi con la stessa priorità assoluta in una lista, ed
+esegue sempre il primo della lista, mentre un nuovo processo che torna in
+stato \textit{runnable} viene sempre inserito in coda alla lista. Se la
+politica scelta è \macro{SCHED\_FIFO} quando il processo viene eseguito viene
+automaticamente rimesso in coda alla lista, e la sua esecuzione continua
+fintanto che non viene bloccato da una richiesta di I/O, o non rilascia
+volontariamente la CPU (in tal caso, tornando nello stato \textit{runnable}
+sarà reinserito in coda alla lista); l'esecuzione viene ripresa subito solo
+nel caso che esso sia stato interrotto da un processo a priorità più alta.
+
+La priorità assoluta può essere riletta indietro dalla funzione
+\func{sched\_getscheduler}, il cui prototipo è:
+\begin{prototype}{sched.h}
+{int sched\_getscheduler(pid\_t pid)}
+ Legge la politica di scheduling per il processo \param{pid}.
+
+ \bodydesc{La funzione ritorna la politica di scheduling in caso di successo
+ e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+ \begin{errlist}
+ \item[\macro{ESRCH}] il processo \param{pid} non esiste.
+ \item[\macro{EINVAL}] il valore di \param{pid} è negativo.
+ \end{errlist}}
+\end{prototype}
+
+La funzione restituisce il valore (secondo la quanto elencato in
+\tabref{tab:proc_sched_policy}) della politica di scheduling per il processo
+specificato; se \param{pid} è nullo viene restituito quello del processo
+chiamante.
+
+Se si intende operare solo sulla priorità assoluta di un processo si possono
+usare le funzioni \func{sched\_setparam} e \func{sched\_getparam}, i cui
+prototipi sono:
+
+\begin{functions}
+ \headdecl{sched.h}
+
+ \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)}
+ Setta la priorità assoluta del processo \param{pid}.
+
+
+ \funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)}
+ Legge la priorità assoluta del processo \param{pid}.
+
+ \bodydesc{La funzione ritorna la priorità in caso di successo
+ e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+ \begin{errlist}
+ \item[\macro{ESRCH}] il processo \param{pid} non esiste.
+ \item[\macro{EINVAL}] il valore di \param{pid} è negativo.
+ \end{errlist}}
+\end{functions}
+L'uso di \func{sched\_setparam} che è del tutto equivalente a
+\func{sched\_setscheduler} con \param{priority} uguale a -1.
\section{Problematiche di programmazione multitasking}
In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t},
il cui accesso è assicurato essere atomico. In pratica comunque si può
assumere che, in ogni piattaforma su cui è implementato Linux, il tipo
-\type{int}, gli altri interi di dimensione inferiore ed i puntatori sono
+\ctyp{int}, gli altri interi di dimensione inferiore ed i puntatori sono
atomici. Non è affatto detto che lo stesso valga per interi di dimensioni
maggiori (in cui l'accesso può comportare più istruzioni in assembler) o per
le strutture. In tutti questi casi è anche opportuno marcare come
-\type{volatile} le variabili che possono essere interessate ad accesso
+\ctyp{volatile} le variabili che possono essere interessate ad accesso
condiviso, onde evitare problemi con le ottimizzazioni del codice.