{int execve(const char *filename, char *const argv[], char *const envp[])}
Esegue il programma contenuto nel file \param{filename}.
- \bodydesc{La funzione ritorna -1 solo in caso di errore, nel qual caso
- caso la \var{errno} può assumere i valori:
+ \bodydesc{La funzione ritorna solo in caso di errore, restituendo -1; nel
+ qual caso \var{errno} può assumere i valori:
\begin{errlist}
\item[\macro{EACCES}] il file non è eseguibile, oppure il filesystem è
montato in \cmd{noexec}, oppure non è un file normale o un interprete.
La scelta di un meccanismo che sia in grado di distribuire in maniera efficace
il tempo di CPU per l'esecuzione dei processi è sempre una questione delicata,
-ed oggetto di numerose ricerche; in ogni caso essa dipende in maniera
-essenziale anche dal tipo di utilizzo che deve essere fatto del sistema.
-
+ed oggetto di numerose ricerche; in generale essa dipende in maniera
+essenziale anche dal tipo di utilizzo che deve essere fatto del sistema, per
+cui non esiste un meccanismo che sia valido per tutti gli usi.
La caratteristica specifica di un sistema multitasking come Linux è quella del
cosiddetto \textit{prehemptive multitasking}: questo significa che al
distribuire al meglio il tempo di CPU fra i vari processi.
La cosa è resa ancora più complicata dal fatto che con le architetture
-multi-processore si introduce anche la problematica dovuta alla scelta di
-quale sia la CPU più opportuna da utilizzare.\footnote{nei processori moderni
- la presenza di ampie cache può rendere poco efficiente trasferire
- l'esecuzione di un processo da una CPU ad un'altra, per cui occorrono
- meccanismi per determinare quale è la migliore scelta fra le diverse CPU.}
-Tutto questo comunque appartiene alle sottigliezze dell'implementazione del
-kernel, e dal punto di vista dei programmi che girano in user space, anche
-quando si hanno più processori (e dei processi che sono eseguiti davvero in
-contemporanea), si può pensare alle politiche di scheduling come concernenti
-la risorsa \textsl{tempo di esecuzione}, la cui assegnazione sarà governata
-dagli stessi meccanismi di scelta di priorità, solo che nel caso di più
-processori sarà a disposizione di più di un processo alla volta.
+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.
I processi non devono solo eseguire del codice, ad esempio molto spesso
-saranno impegnati in operazioni di I/O, possono venire bloccati da un
-comando dal terminale, 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.
+saranno impegnati in operazioni di I/O, possono venire bloccati da un comando
+dal terminale, 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
+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 di
-
+\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
\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 spesso non è
-neanche la più importante. Per questo motivo non è affatto detto che dare ad
-un programma la massima priorità di esecuzione abbia risultati significativi
-in termini di prestazioni.
-
-
-
-
-Una delle caratteristiche c
-
-la priorità assoluta viene invece ignorata per quelli che sono bloccati su una
-richiesta di I/O o in stato di \textit{sleep}
-
-
+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à
In generale quello che succede in tutti gli Unix moderni è che ai processi
normali viene sempre data una priorità assoluta pari a zero, e la decisione di
-assegnazione della CPU è fatta solo in base ad una priorità dinamica che è
-calcolata indipendentemente. È tuttavia possibile assegnare anche una priorità
-assoluta nel qual caso un processo avrà la precedenza su tutti gli altri di
-priorità inferiore che saranno eseguiti solo quando quest'ultimo non avrà
+assegnazione della CPU è fatta solo con il meccanismo tradizionale della
+priorità dinamica. In Linux tuttavia è possibile assegnare anche una priorità
+assoluta, nel qual caso un processo avrà la precedenza su tutti gli altri di
+priorità inferiore, che saranno eseguiti solo quando quest'ultimo non avrà
bisogno della CPU.
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}; 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.
+
+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 è:
+\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.
+ \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à. 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
+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.
+
+ \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.
+ \end{errlist}}
+\end{prototype}
+
+