X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=prochand.tex;h=69da2ce7199b032d725e6ca47e045a4d92bdf92c;hp=6beef58d08f7d02e31c9d8896ff3da33bd475a16;hb=b51bcef6bcf8c8622107b8ab8a22626dbdf6ba96;hpb=e0cc9bf7b67899cae825bc33819aaac05c40561e diff --git a/prochand.tex b/prochand.tex index 6beef58..69da2ce 100644 --- a/prochand.tex +++ b/prochand.tex @@ -1,6 +1,6 @@ %% prochand.tex %% -%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Prefazione", @@ -43,7 +43,7 @@ caratteristiche di Unix (che esamineremo in dettaglio pi qualunque processo può a sua volta generarne altri, detti processi figli (\textit{child process}). Ogni processo è identificato presso il sistema da un numero univoco, il cosiddetto \textit{process identifier} o, più brevemente, -\acr{pid}, assegnato in forma progressiva (vedi \secref{sec:proc_pid}) quando +\acr{pid}, assegnato in forma progressiva (vedi sez.~\ref{sec:proc_pid}) quando il processo viene creato. Una seconda caratteristica di un sistema Unix è che la generazione di un @@ -65,7 +65,7 @@ Ovviamente \cmd{init} partire tutti gli altri processi necessari al funzionamento del sistema, inoltre \cmd{init} è essenziale per svolgere una serie di compiti amministrativi nelle operazioni ordinarie del sistema (torneremo su alcuni di -essi in \secref{sec:proc_termination}) e non può mai essere terminato. La +essi in sez.~\ref{sec:proc_termination}) e non può mai essere terminato. La struttura del sistema comunque consente di lanciare al posto di \cmd{init} qualunque altro programma, e in casi di emergenza (ad esempio se il file di \cmd{init} si fosse corrotto) è ad esempio possibile lanciare una shell al suo @@ -120,19 +120,20 @@ Dato che tutti i processi attivi nel sistema sono comunque generati da possono classificare i processi con la relazione padre/figlio in un'organizzazione gerarchica ad albero, in maniera analoga a come i file sono organizzati in un albero di directory (si veda -\secref{sec:file_organization}); in \figref{fig:proc_tree} si è mostrato il +sez.~\ref{sec:file_organization}); in fig.~\ref{fig:proc_tree} si è mostrato il risultato del comando \cmd{pstree} che permette di visualizzare questa struttura, alla cui base c'è \cmd{init} che è progenitore di tutti gli altri processi. Il kernel mantiene una tabella dei processi attivi, la cosiddetta -\textit{process table}; per ciascun processo viene mantenuta una voce nella -tabella dei processi costituita da una struttura \struct{task\_struct}, che -contiene tutte le informazioni rilevanti per quel processo. Tutte le strutture -usate a questo scopo sono dichiarate nell'header file \file{linux/sched.h}, ed -uno schema semplificato, che riporta la struttura delle principali informazioni -contenute nella \struct{task\_struct} (che in seguito incontreremo a più -riprese), è mostrato in \figref{fig:proc_task_struct}. +\textit{process table}; per ciascun processo viene mantenuta una voce, +costituita da una struttura \struct{task\_struct}, nella tabella dei processi +che contiene tutte le informazioni rilevanti per quel processo. Tutte le +strutture usate a questo scopo sono dichiarate nell'header file +\file{linux/sched.h}, ed uno schema semplificato, che riporta la struttura +delle principali informazioni contenute nella \struct{task\_struct} (che in +seguito incontreremo a più riprese), è mostrato in +fig.~\ref{fig:proc_task_struct}. \begin{figure}[htb] \centering @@ -142,8 +143,7 @@ riprese), \label{fig:proc_task_struct} \end{figure} - -Come accennato in \secref{sec:intro_unix_struct} è lo +Come accennato in sez.~\ref{sec:intro_unix_struct} è lo \textit{scheduler}\index{scheduler} che decide quale processo mettere in esecuzione; esso viene eseguito ad ogni system call ed ad ogni interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa @@ -154,35 +154,34 @@ interrupt periodico secondo la frequenza specificata dalla costante Hertz.\footnote{Il valore usuale di questa costante è 100, per tutte le architetture eccetto l'alpha, per la quale è 1000. Occorre fare attenzione a non confondere questo valore con quello dei clock tick (vedi - \secref{sec:sys_unix_time}).} + sez.~\ref{sec:sys_unix_time}).} %Si ha cioè un interrupt dal timer ogni centesimo di secondo. Ogni volta che viene eseguito, lo \textit{scheduler}\index{scheduler} effettua il calcolo delle priorità dei vari processi attivi (torneremo su questo in -\secref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in +sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in esecuzione fino alla successiva invocazione. \subsection{Una panoramica sulle funzioni fondamentali} \label{sec:proc_handling_intro} -I processi vengono creati dalla funzione \func{fork}; in molti unix questa è -una system call, Linux però usa un'altra nomenclatura, e la funzione -\func{fork} è basata a sua volta sulla system call \func{\_\_clone}, che viene -usata anche per generare i \textit{thread}. Il processo figlio creato dalla -\func{fork} è una copia identica del processo processo padre, ma ha un nuovo -\acr{pid} e viene eseguito in maniera indipendente (le differenze fra padre e -figlio sono affrontate in dettaglio in \secref{sec:proc_fork}). +In un sistema unix-like i processi vengono sempre creati da altri processi +tramite la funzione \func{fork}; il nuovo processo (che viene chiamato +\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo +processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene +eseguito in maniera indipendente (le differenze fra padre e figlio sono +affrontate in dettaglio in sez.~\ref{sec:proc_fork}). Se si vuole che il processo padre si fermi fino alla conclusione del processo figlio questo deve essere specificato subito dopo la \func{fork} chiamando la funzione \func{wait} o la funzione \func{waitpid} (si veda -\secref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione +sez.~\ref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione abbastanza limitata sulle cause della terminazione del processo figlio. Quando un processo ha concluso il suo compito o ha incontrato un errore non risolvibile esso può essere terminato con la funzione \func{exit} (si veda -quanto discusso in \secref{sec:proc_conclusion}). La vita del processo però +quanto discusso in sez.~\ref{sec:proc_conclusion}). La vita del processo però termina solo quando la notifica della sua conclusione viene ricevuta dal processo padre, a quel punto tutte le risorse allocate nel sistema ad esso associate vengono rilasciate. @@ -196,7 +195,7 @@ coi processi che Il programma che un processo sta eseguendo si chiama immagine del processo (o \textit{process image}), le funzioni della famiglia \func{exec} permettono di -caricare un'altro programma da disco sostituendo quest'ultimo all'immagine +caricare un altro programma da disco sostituendo quest'ultimo all'immagine corrente; questo fa sì che l'immagine precedente venga completamente cancellata. Questo significa che quando il nuovo programma termina, anche il processo termina, e non si può tornare alla precedente immagine. @@ -231,18 +230,18 @@ intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato Il \acr{pid} viene assegnato in forma progressiva\footnote{in genere viene assegnato il numero successivo a quello usato per l'ultimo processo creato, a meno che questo numero non sia già utilizzato per un altro \acr{pid}, - \acr{pgid} o \acr{sid} (vedi \secref{sec:sess_proc_group}).} ogni volta che -un nuovo processo viene creato, fino ad un limite che, essendo il \acr{pid} un -numero positivo memorizzato in un intero a 16 bit, arriva ad un massimo di -32768. Oltre questo valore l'assegnazione riparte dal numero più basso -disponibile a partire da un minimo di 300,\footnote{questi valori, fino al - kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in \file{threads.h} - e direttamente in \file{fork.c}, con il kernel 2.5.x e la nuova interfaccia - per i thread creata da Ingo Molnar anche il meccanismo di allocazione dei - \acr{pid} è stato modificato.} che serve a riservare i \acr{pid} più bassi -ai processi eseguiti dal direttamente dal kernel. Per questo motivo, come -visto in \secref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha -sempre il \acr{pid} uguale a uno. + \acr{pgid} o \acr{sid} (vedi sez.~\ref{sec:sess_proc_group}).} ogni volta +che un nuovo processo viene creato, fino ad un limite che, essendo il +\acr{pid} un numero positivo memorizzato in un intero a 16 bit, arriva ad un +massimo di 32768. Oltre questo valore l'assegnazione riparte dal numero più +basso disponibile a partire da un minimo di 300,\footnote{questi valori, fino + al kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in + \file{threads.h} e direttamente in \file{fork.c}, con il kernel 2.5.x e la + nuova interfaccia per i thread creata da Ingo Molnar anche il meccanismo di + allocazione dei \acr{pid} è stato modificato.} che serve a riservare i +\acr{pid} più bassi ai processi eseguiti direttamente dal kernel. Per questo +motivo, come visto in sez.~\ref{sec:proc_hierarchy}, il processo di avvio +(\cmd{init}) ha sempre il \acr{pid} uguale a uno. Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui sono stati creati, questo viene chiamato in genere \acr{ppid} (da @@ -263,30 +262,30 @@ prototipi sono: \bodydesc{Entrambe le funzioni non riportano condizioni di errore.} \end{functions} \noindent esempi dell'uso di queste funzioni sono riportati in -\figref{fig:proc_fork_code}, nel programma di esempio \file{ForkTest.c}. +fig.~\ref{fig:proc_fork_code}, nel programma \file{ForkTest.c}. Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende un candidato per generare ulteriori indicatori associati al processo di cui diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la -funzione \func{tmpname} (si veda \secref{sec:file_temp_file}) usa il \acr{pid} -per generare un pathname univoco, che non potrà essere replicato da un'altro -processo che usi la stessa funzione. +funzione \func{tmpname} (si veda sez.~\ref{sec:file_temp_file}) usa il +\acr{pid} per generare un pathname univoco, che non potrà essere replicato da +un altro processo che usi la stessa funzione. Tutti i processi figli dello stesso processo padre sono detti \textit{sibling}, questa è una delle relazioni usate nel \textsl{controllo di sessione}, in cui si raggruppano i processi creati su uno stesso terminale, o relativi allo stesso login. Torneremo su questo argomento in dettaglio in -\secref{cha:session}, dove esamineremo gli altri identificativi associati ad +cap.~\ref{cha:session}, dove esamineremo gli altri identificativi associati ad un processo e le varie relazioni fra processi utilizzate per definire una sessione. Oltre al \acr{pid} e al \acr{ppid}, (e a quelli che vedremo in -\secref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni +sez.~\ref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni processo vengono associati degli altri identificatori che vengono usati per il controllo di accesso. Questi servono per determinare se un processo può eseguire o meno le operazioni richieste, a seconda dei privilegi e dell'identità di chi lo ha posto in esecuzione; l'argomento è complesso e sarà -affrontato in dettaglio in \secref{sec:proc_perms}. +affrontato in dettaglio in sez.~\ref{sec:proc_perms}. \subsection{La funzione \func{fork}} @@ -307,7 +306,7 @@ prototipo della funzione zero al figlio; ritorna -1 al padre (senza creare il figlio) in caso di errore; \var{errno} può assumere i valori: \begin{errlist} - \item[\errcode{EAGAIN}] non ci sono risorse sufficienti per creare un'altro + \item[\errcode{EAGAIN}] non ci sono risorse sufficienti per creare un altro processo (per allocare la tabella delle pagine e le strutture del task) o si è esaurito il numero di processi disponibili. \item[\errcode{ENOMEM}] non è stato possibile allocare la memoria per le @@ -319,7 +318,7 @@ Dopo il successo dell'esecuzione di una \func{fork} sia il processo padre che il processo figlio continuano ad essere eseguiti normalmente a partire dall'istruzione successiva alla \func{fork}; il processo figlio è però una copia del padre, e riceve una copia dei segmenti di testo, stack e dati (vedi -\secref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del +sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del padre. Si tenga presente però che la memoria è copiata, non condivisa, pertanto padre e figlio vedono variabili diverse. @@ -345,57 +344,15 @@ La scelta di questi valori di ritorno non avere più figli, ed il valore di ritorno di \func{fork} è l'unico modo che gli permette di identificare quello appena creato; al contrario un figlio ha sempre un solo padre (il cui \acr{pid} può sempre essere ottenuto con -\func{getppid}, vedi \secref{sec:proc_pid}) per cui si usa il valore nullo, +\func{getppid}, vedi sez.~\ref{sec:proc_pid}) per cui si usa il valore nullo, che non è il \acr{pid} di nessun processo. \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -#include /* error definitions and routines */ -#include /* C standard library */ -#include /* unix standard library */ -#include /* standard I/O library */ -#include /* string functions */ - -/* Help printing routine */ -void usage(void); - -int main(int argc, char *argv[]) -{ -/* - * Variables definition - */ - int nchild, i; - pid_t pid; - int wait_child = 0; - int wait_parent = 0; - int wait_end = 0; - ... /* handling options */ - nchild = atoi(argv[optind]); - printf("Test for forking %d child\n", nchild); - /* loop to fork children */ - for (i=0; i} ed elencate in \tabref{tab:proc_status_macro} (si tenga +\file{} ed elencate in tab.~\ref{tab:proc_status_macro} (si tenga presente che queste macro prendono come parametro la variabile di tipo \ctyp{int} puntata da \param{status}). Si tenga conto che nel caso di conclusione anomala il valore restituito da \val{WTERMSIG} può essere confrontato con le costanti definite in -\file{signal.h} ed elencate in \tabref{tab:sig_signal_list}, e stampato usando -le apposite funzioni trattate in \secref{sec:sig_strsignal}. +\file{signal.h} ed elencate in tab.~\ref{tab:sig_signal_list}, e stampato +usando le apposite funzioni trattate in sez.~\ref{sec:sig_strsignal}. \subsection{Le funzioni \func{wait3} e \func{wait4}} @@ -1076,8 +1037,8 @@ sono: \noindent la struttura \struct{rusage} è definita in \file{sys/resource.h}, e viene utilizzata anche dalla funzione \func{getrusage} (vedi -\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un -processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}. +sez.~\ref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un +processo; la sua definizione è riportata in fig.~\ref{fig:sys_rusage_struct}. \subsection{Le funzioni \func{exec}} @@ -1094,7 +1055,7 @@ disco. Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata famiglia di funzioni) che possono essere usate per questo compito, in realtà -(come mostrato in \figref{fig:proc_exec_relat}), sono tutte un front-end a +(come mostrato in fig.~\ref{fig:proc_exec_relat}), sono tutte un front-end a \funcd{execve}. Il prototipo di quest'ultima è: \begin{prototype}{unistd.h} {int execve(const char *filename, char *const argv[], char *const envp[])} @@ -1105,8 +1066,8 @@ famiglia di funzioni) che possono essere usate per questo compito, in realt \begin{errlist} \item[\errcode{EACCES}] il file non è eseguibile, oppure il filesystem è montato in \cmd{noexec}, oppure non è un file regolare o un interprete. - \item[\errcode{EPERM}] il file ha i bit \acr{suid} o \acr{sgid}, l'utente non - è root, e o il processo viene tracciato, o il filesystem è montato con + \item[\errcode{EPERM}] il file ha i bit \acr{suid} o \acr{sgid}, l'utente + non è root, il processo viene tracciato, o il filesystem è montato con l'opzione \cmd{nosuid}. \item[\errcode{ENOEXEC}] il file è in un formato non eseguibile o non riconosciuto come tale, o compilato per un'altra architettura. @@ -1156,7 +1117,7 @@ linea di comando e l'ambiente ricevuti dal nuovo processo. \end{functions} Per capire meglio le differenze fra le funzioni della famiglia si può fare -riferimento allo specchietto riportato in \tabref{tab:proc_exec_scheme}. La +riferimento allo specchietto riportato in tab.~\ref{tab:proc_exec_scheme}. La prima differenza riguarda le modalità di passaggio dei parametri che poi andranno a costituire gli argomenti a linea di comando (cioè i valori di \param{argv} e \param{argc} visti dalla funzione \func{main} del programma @@ -1170,9 +1131,7 @@ questo vettore \emph{deve} essere terminato da un puntatore nullo. Nel secondo caso le stringhe degli argomenti sono passate alla funzione come lista di puntatori, nella forma: -\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} - char *arg0, char *arg1, ..., char *argn, NULL -\end{lstlisting} +\includecodesnip{listati/char_list.c} che deve essere terminata da un puntatore nullo. In entrambi i casi vale la convenzione che il primo argomento (\var{arg0} o \var{argv[0]}) viene usato per indicare il nome del file che contiene il programma che verrà eseguito. @@ -1208,7 +1167,7 @@ La seconda differenza fra le funzioni riguarda le modalit specifica il programma che si vuole eseguire. Con lo mnemonico \code{p} si indicano le due funzioni che replicano il comportamento della shell nello specificare il comando da eseguire; quando il parametro \param{file} non -contiene una \file{/} esso viene considerato come un nome di programma, e +contiene una ``\file{/}'' esso viene considerato come un nome di programma, e viene eseguita automaticamente una ricerca fra i file presenti nella lista di directory specificate dalla variabile di ambiente \var{PATH}. Il file che viene posto in esecuzione è il primo che viene trovato. Se si ha un errore @@ -1224,7 +1183,7 @@ indicato dall'argomento \param{path}, che viene interpretato come il \begin{figure}[htb] \centering - \includegraphics[width=15cm]{img/exec_rel} + \includegraphics[width=16cm]{img/exec_rel} \caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.} \label{fig:proc_exec_relat} \end{figure} @@ -1233,7 +1192,7 @@ La terza differenza Con lo mnemonico \code{e} vengono indicate quelle funzioni che necessitano di un vettore di parametri \var{envp[]} analogo a quello usato per gli argomenti a riga di comando (terminato quindi da un \val{NULL}), le altre usano il -valore della variabile \var{environ} (vedi \secref{sec:proc_environ}) del +valore della variabile \var{environ} (vedi sez.~\ref{sec:proc_environ}) del processo di partenza per costruire l'ambiente. Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da @@ -1243,21 +1202,21 @@ la lista completa \item il \textit{process id} (\acr{pid}) ed il \textit{parent process id} (\acr{ppid}). \item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i - \textsl{group-ID supplementari} (vedi \secref{sec:proc_access_id}). + \textsl{group-ID supplementari} (vedi sez.~\ref{sec:proc_access_id}). \item il \textit{session id} (\acr{sid}) ed il \textit{process group-ID} - (\acr{pgid}), vedi \secref{sec:sess_proc_group}. -\item il terminale di controllo (vedi \secref{sec:sess_ctrl_term}). -\item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}). + (\acr{pgid}), vedi sez.~\ref{sec:sess_proc_group}. +\item il terminale di controllo (vedi sez.~\ref{sec:sess_ctrl_term}). +\item il tempo restante ad un allarme (vedi sez.~\ref{sec:sig_alarm_abort}). \item la directory radice e la directory di lavoro corrente (vedi - \secref{sec:file_work_dir}). + sez.~\ref{sec:file_work_dir}). \item la maschera di creazione dei file (\var{umask}, vedi - \secref{sec:file_umask}) ed i \textit{lock} sui file (vedi - \secref{sec:file_locking}). + sez.~\ref{sec:file_umask}) ed i \textit{lock} sui file (vedi + sez.~\ref{sec:file_locking}). \item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda - \secref{sec:sig_sigmask}). -\item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}). + sez.~\ref{sec:sig_sigmask}). +\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit}). \item i valori delle variabili \var{tms\_utime}, \var{tms\_stime}, - \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:sys_cpu_times}). + \var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times}). \end{itemize*} Inoltre i segnali che sono stati impostati per essere ignorati nel processo @@ -1265,11 +1224,11 @@ chiamante mantengono la stessa impostazione pure nel nuovo programma, tutti gli altri segnali vengono impostati alla loro azione predefinita. Un caso speciale è il segnale \const{SIGCHLD} che, quando impostato a \const{SIG\_IGN}, può anche non essere reimpostato a \const{SIG\_DFL} (si veda -\secref{sec:sig_gen_beha}). +sez.~\ref{sec:sig_gen_beha}). La gestione dei file aperti dipende dal valore che ha il flag di \textit{close-on-exec}\index{close-on-exec} (vedi anche -\secref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è +sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è impostato vengono chiusi, tutti gli altri file restano aperti. Questo significa che il comportamento predefinito è che i file restano aperti attraverso una \func{exec}, a meno di una chiamata esplicita a \func{fcntl} @@ -1277,18 +1236,18 @@ che imposti il suddetto flag. Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse attraverso una \func{exec}, in genere questo è fatto dalla funzione -\func{opendir} (vedi \secref{sec:file_dir_read}) che effettua da sola +\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola l'impostazione del flag di \textit{close-on-exec}\index{close-on-exec} sulle directory che apre, in maniera trasparente all'utente. Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale} restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il significato -di questi identificatori è trattato in \secref{sec:proc_access_id}), tranne +di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne quando il file che si va ad eseguire abbia o il \acr{suid} bit o lo \acr{sgid} bit impostato, in questo caso l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} vengono impostati rispettivamente all'utente o al -gruppo cui il file appartiene (per i dettagli vedi \secref{sec:proc_perms}). +gruppo cui il file appartiene (per i dettagli vedi sez.~\ref{sec:proc_perms}). Se il file da eseguire è in formato \emph{a.out} e necessita di librerie condivise, viene lanciato il \textit{linker} dinamico \cmd{ld.so} prima del @@ -1299,8 +1258,8 @@ in genere questo \acr{libc5}, e \file{/lib/ld-linux.so.2} per programmi linkati con le \acr{glibc}. Infine nel caso il file sia uno script esso deve iniziare con una linea nella forma \cmd{\#!/path/to/interpreter} dove l'interprete indicato -deve esse un valido programma (binario, non un altro script) che verrà -chiamato come se si fosse eseguito il comando \cmd{interpreter [arg] +deve esse un programma valido (binario, non un altro script) che verrà +chiamato come se si fosse eseguito il comando \cmd{interpreter [argomenti] filename}. Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è @@ -1325,7 +1284,7 @@ problematiche connesse ad una gestione accorta dei privilegi. \subsection{Gli identificatori del controllo di accesso} \label{sec:proc_access_id} -Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in +Come accennato in sez.~\ref{sec:intro_multiuser} il modello base\footnote{in realtà già esistono estensioni di questo modello base, che lo rendono più flessibile e controllabile, come le \textit{capabilities}, le ACL per i file o il \textit{Mandatory Access Control} di SELinux; inoltre basandosi sul @@ -1346,7 +1305,7 @@ Abbiamo gi identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per identificare uno specifico utente o un gruppo di utenti, per poi poter controllare che essi siano autorizzati a compiere le operazioni richieste. Ad -esempio in \secref{sec:file_access_control} vedremo come ad ogni file vengano +esempio in sez.~\ref{sec:file_access_control} vedremo come ad ogni file vengano associati un utente ed un gruppo (i suoi \textsl{proprietari}, indicati appunto tramite un \acr{uid} ed un \acr{gid}) che vengono controllati dal kernel nella gestione dei permessi di accesso. @@ -1364,7 +1323,8 @@ prevedono che i processi abbiano almeno due gruppi di identificatori, chiamati rispettivamente \textit{real} ed \textit{effective} (cioè \textsl{reali} ed \textsl{effettivi}). Nel caso di Linux si aggiungono poi altri due gruppi, il \textit{saved} (\textsl{salvati}) ed il \textit{filesystem} (\textsl{di - filesystem}), secondo la situazione illustrata in \tabref{tab:proc_uid_gid}. + filesystem}), secondo la situazione illustrata in +tab.~\ref{tab:proc_uid_gid}. \begin{table}[htb] \footnotesize @@ -1408,7 +1368,7 @@ Al primo gruppo appartengono l'\textsl{user-ID reale} ed il \textsl{group-ID reale}: questi vengono impostati al login ai valori corrispondenti all'utente con cui si accede al sistema (e relativo gruppo principale). Servono per l'identificazione dell'utente e normalmente non vengono mai -cambiati. In realtà vedremo (in \secref{sec:proc_setuid}) che è possibile +cambiati. In realtà vedremo (in sez.~\ref{sec:proc_setuid}) che è possibile modificarli, ma solo ad un processo che abbia i privilegi di amministratore; questa possibilità è usata proprio dal programma \cmd{login} che, una volta completata la procedura di autenticazione, lancia una shell per la quale @@ -1420,16 +1380,16 @@ Al secondo gruppo appartengono lo \textsl{user-ID effettivo} ed il supplementari} dei gruppi dei quali l'utente fa parte). Questi sono invece gli identificatori usati nella verifiche dei permessi del processo e per il controllo di accesso ai file (argomento affrontato in dettaglio in -\secref{sec:file_perm_overview}). +sez.~\ref{sec:file_perm_overview}). Questi identificatori normalmente sono identici ai corrispondenti del gruppo \textit{real} tranne nel caso in cui, come accennato in -\secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit +sez.~\ref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit \acr{suid} o \acr{sgid} impostati (il significato di questi bit è affrontato -in dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno +in dettaglio in sez.~\ref{sec:file_suid_sgid}). In questo caso essi saranno impostati all'utente e al gruppo proprietari del file. Questo consente, per programmi in cui ci sia necessità, di dare a qualunque utente normale -privilegi o permessi di un'altro (o dell'amministratore). +privilegi o permessi di un altro (o dell'amministratore). Come nel caso del \acr{pid} e del \acr{ppid}, anche tutti questi identificatori possono essere letti attraverso le rispettive funzioni: @@ -1460,11 +1420,11 @@ maggiori privilegi necessari, una volta che si siano effettuate le operazioni per i quali erano richiesti, e a poterli eventualmente recuperare in caso servano di nuovo. -Questo in Linux viene fatto usando altri gli altri due gruppi di -identificatori, il \textit{saved} ed il \textit{filesystem}. Il primo gruppo è -lo stesso usato in SVr4, e previsto dallo standard POSIX quando è definita la -costante \macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a cuore la - portabilità del programma su altri Unix è buona norma controllare sempre la +Questo in Linux viene fatto usando altri due gruppi di identificatori, il +\textit{saved} ed il \textit{filesystem}. Il primo gruppo è lo stesso usato in +SVr4, e previsto dallo standard POSIX quando è definita la costante +\macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a cuore la portabilità + del programma su altri Unix è buona norma controllare sempre la disponibilità di queste funzioni controllando se questa costante è definita.} il secondo gruppo è specifico di Linux e viene usato per migliorare la sicurezza con NFS. @@ -1473,16 +1433,16 @@ L'\textsl{user-ID salvato} ed il \textsl{group-ID salvato} sono copie dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo} del processo padre, e vengono impostati dalla funzione \func{exec} all'avvio del processo, come copie dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo} -dopo che questo sono stati impostati tenendo conto di eventuali \acr{suid} o +dopo che questi sono stati impostati tenendo conto di eventuali \acr{suid} o \acr{sgid}. Essi quindi consentono di tenere traccia di quale fossero utente e gruppo effettivi all'inizio dell'esecuzione di un nuovo programma. L'\textsl{user-ID di filesystem} e il \textsl{group-ID di filesystem} sono un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS -(torneremo sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una +(torneremo sull'argomento in sez.~\ref{sec:proc_setfsuid}). Essi sono una replica dei corrispondenti identificatori del gruppo \textit{effective}, ai quali si sostituiscono per tutte le operazioni di verifica dei permessi -relativi ai file (trattate in \secref{sec:file_perm_overview}). Ogni +relativi ai file (trattate in sez.~\ref{sec:file_perm_overview}). Ogni cambiamento effettuato sugli identificatori effettivi viene automaticamente riportato su di essi, per cui in condizioni normali si può tranquillamente ignorarne l'esistenza, in quanto saranno del tutto equivalenti ai precedenti. @@ -1493,7 +1453,7 @@ ignorarne l'esistenza, in quanto saranno del tutto equivalenti ai precedenti. Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo di appartenenza) ad un processo sono rispettivamente \funcd{setuid} e -\funcd{setgid}; come accennato in \secref{sec:proc_access_id} in Linux esse +\funcd{setgid}; come accennato in sez.~\ref{sec:proc_access_id} in Linux esse seguono la semantica POSIX che prevede l'esistenza dell'\textit{user-ID salvato} e del \textit{group-ID salvato}; i loro prototipi sono: \begin{functions} @@ -1526,8 +1486,8 @@ all'\textsl{user-ID salvato}. Negli altri casi viene segnalato un errore (con Come accennato l'uso principale di queste funzioni è quello di poter consentire ad un programma con i bit \acr{suid} o \acr{sgid} impostati (vedi -\secref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} a quello -dell'utente che ha lanciato il programma, effettuare il lavoro che non +sez.~\ref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} a +quello dell'utente che ha lanciato il programma, effettuare il lavoro che non necessita di privilegi aggiuntivi, ed eventualmente tornare indietro. Come esempio per chiarire l'uso di queste funzioni prendiamo quello con cui @@ -1578,22 +1538,23 @@ funzione avr consentendo l'accesso a \file{/var/log/utmp}. Occorre però tenere conto che tutto questo non è possibile con un processo con -i privilegi di root, in tal caso infatti l'esecuzione una \func{setuid} -comporta il cambiamento di tutti gli identificatori associati al processo, -rendendo impossibile riguadagnare i privilegi di amministratore. Questo -comportamento è corretto per l'uso che ne fa \cmd{login} una volta che crea -una nuova shell per l'utente; ma quando si vuole cambiare soltanto +i privilegi di amministratore, in tal caso infatti l'esecuzione di una +\func{setuid} comporta il cambiamento di tutti gli identificatori associati al +processo, rendendo impossibile riguadagnare i privilegi di amministratore. +Questo comportamento è corretto per l'uso che ne fa \cmd{login} una volta che +crea una nuova shell per l'utente; ma quando si vuole cambiare soltanto l'\textsl{user-ID effettivo} del processo per cedere i privilegi occorre -ricorrere ad altre funzioni (si veda ad esempio \secref{sec:proc_seteuid}). +ricorrere ad altre funzioni (si veda ad esempio sez.~\ref{sec:proc_seteuid}). -\subsection{Le funzioni \func{setreuid} e \func{setresuid}} +\subsection{Le funzioni \func{setreuid} e \func{setregid}} \label{sec:proc_setreuid} -Queste due funzioni derivano da BSD che, non supportando\footnote{almeno fino - alla versione 4.3+BSD TODO, FIXME verificare e aggiornare la nota.} gli -identificatori del gruppo \textit{saved}, le usa per poter scambiare fra di -loro \textit{effective} e \textit{real}. I loro prototipi sono: +Le due funzioni \funcd{setreuid} e \funcd{setregid} derivano da BSD che, non +supportando\footnote{almeno fino alla versione 4.3+BSD TODO, FIXME verificare + e aggiornare la nota.} gli identificatori del gruppo \textit{saved}, le usa +per poter scambiare fra di loro \textit{effective} e \textit{real}. I +rispettivi prototipi sono: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} @@ -1611,12 +1572,12 @@ specificati da \param{rgid} e \param{egid}. \end{functions} La due funzioni sono analoghe ed il loro comportamento è identico; quanto -detto per la prima prima riguardo l'user-ID, si applica immediatamente alla -seconda per il group-ID. I processi non privilegiati possono impostare solo i -valori del loro user-ID effettivo o reale; valori diversi comportano il -fallimento della chiamata; l'amministratore invece può specificare un valore -qualunque. Specificando un argomento di valore -1 l'identificatore -corrispondente verrà lasciato inalterato. +detto per la prima riguardo l'user-ID, si applica immediatamente alla seconda +per il group-ID. I processi non privilegiati possono impostare solo i valori +del loro user-ID effettivo o reale; valori diversi comportano il fallimento +della chiamata; l'amministratore invece può specificare un valore qualunque. +Specificando un argomento di valore -1 l'identificatore corrispondente verrà +lasciato inalterato. Con queste funzioni si possono scambiare fra loro gli user-ID reale e effettivo, e pertanto è possibile implementare un comportamento simile a @@ -1642,12 +1603,13 @@ corrente, l'user-ID salvato viene automaticamente uniformato al valore dell'user-ID effettivo. -\subsection{Le funzioni \funcd{seteuid} e \funcd{setegid}} +\subsection{Le funzioni \func{seteuid} e \func{setegid}} \label{sec:proc_seteuid} -Queste funzioni sono un'estensione allo standard POSIX.1 (ma sono comunque -supportate dalla maggior parte degli Unix) e vengono usate per cambiare gli -identificatori del gruppo \textit{effective}; i loro prototipi sono: +Le due funzioni \funcd{seteuid} e \funcd{setegid} sono un'estensione allo +standard POSIX.1 (ma sono comunque supportate dalla maggior parte degli Unix) +e vengono usate per cambiare gli identificatori del gruppo \textit{effective}; +i loro prototipi sono: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} @@ -1670,12 +1632,13 @@ all'amministratore di impostare solo l'user-ID effettivo, dato che l'uso normale di \func{setuid} comporta l'impostazione di tutti gli identificatori. -\subsection{Le funzioni \funcd{setresuid} e \funcd{setresgid}} +\subsection{Le funzioni \func{setresuid} e \func{setresgid}} \label{sec:proc_setresuid} -Queste due funzioni sono un'estensione introdotta in Linux dal kernel 2.1.44, -e permettono un completo controllo su tutti gli identificatori (\textit{real}, -\textit{effective} e \textit{saved}), i prototipi sono: +Le due funzioni \funcd{setresuid} e \funcd{setresgid} sono un'estensione +introdotta in Linux,\footnote{a partire dal kernel 2.1.44.} e permettono un +completo controllo su tutti e tre i gruppi di identificatori (\textit{real}, +\textit{effective} e \textit{saved}), i loro prototipi sono: \begin{functions} \headdecl{unistd.h} \headdecl{sys/types.h} @@ -1722,33 +1685,35 @@ corrente. Anche queste funzioni sono un'estensione specifica di Linux, e non richiedono nessun privilegio. I valori sono restituiti negli argomenti, che vanno -specificati come puntatori (è un'altro esempio di \textit{value result - argument}). Si noti che queste funzioni sono le uniche in grado di leggere -gli identificatori del gruppo \textit{saved}. +specificati come puntatori (è un altro esempio di +\index{\textit{value~result~argument}}\textit{value result argument}). Si noti +che queste funzioni sono le uniche in grado di leggere gli identificatori del +gruppo \textit{saved}. \subsection{Le funzioni \func{setfsuid} e \func{setfsgid}} \label{sec:proc_setfsuid} -Queste funzioni sono usate per impostare gli identificatori del gruppo -\textit{filesystem} che usati da Linux per il controllo dell'accesso ai file. -Come già accennato in \secref{sec:proc_access_id} Linux definisce questo -ulteriore gruppo di identificatori, che di norma sono assolutamente -equivalenti a quelli del gruppo \textit{effective}, dato che ogni cambiamento -di questi ultimi viene immediatamente riportato su di essi. +Queste funzioni servono per impostare gli identificatori del gruppo +\textit{filesystem} che sono usati da Linux per il controllo dell'accesso ai +file. Come già accennato in sez.~\ref{sec:proc_access_id} Linux definisce +questo ulteriore gruppo di identificatori, che in circostanze normali sono +assolutamente equivalenti a quelli del gruppo \textit{effective}, dato che +ogni cambiamento di questi ultimi viene immediatamente riportato su di essi. C'è un solo caso in cui si ha necessità di introdurre una differenza fra gli identificatori dei gruppi \textit{effective} e \textit{filesystem}, ed è per ovviare ad un problema di sicurezza che si presenta quando si deve -implementare un server NFS. Il server NFS infatti deve poter cambiare -l'identificatore con cui accede ai file per assumere l'identità del singolo -utente remoto, ma se questo viene fatto cambiando l'user-ID effettivo o -l'user-ID reale il server si espone alla ricezione di eventuali segnali ostili -da parte dell'utente di cui ha temporaneamente assunto l'identità. Cambiando -solo l'user-ID di filesystem si ottengono i privilegi necessari per accedere ai -file, mantenendo quelli originari per quanto riguarda tutti gli altri -controlli di accesso, così che l'utente non possa inviare segnali al server -NFS. +implementare un server NFS. + +Il server NFS infatti deve poter cambiare l'identificatore con cui accede ai +file per assumere l'identità del singolo utente remoto, ma se questo viene +fatto cambiando l'user-ID effettivo o l'user-ID reale il server si espone alla +ricezione di eventuali segnali ostili da parte dell'utente di cui ha +temporaneamente assunto l'identità. Cambiando solo l'user-ID di filesystem si +ottengono i privilegi necessari per accedere ai file, mantenendo quelli +originari per quanto riguarda tutti gli altri controlli di accesso, così che +l'utente non possa inviare segnali al server NFS. Le due funzioni usate per cambiare questi identificatori sono \funcd{setfsuid} e \funcd{setfsgid}, ovviamente sono specifiche di Linux e non devono essere @@ -1775,13 +1740,16 @@ coincide con uno dei di quelli del gruppo \textit{real}, \textit{effective} o \label{sec:proc_setgroups} Le ultime funzioni che esamineremo sono quelle che permettono di operare sui -gruppi supplementari. Ogni processo può avere fino a \const{NGROUPS\_MAX} -gruppi supplementari in aggiunta al gruppo primario, questi vengono ereditati -dal processo padre e possono essere cambiati con queste funzioni. - -La funzione che permette di leggere i gruppi supplementari è -\funcd{getgroups}; questa funzione è definita nello standard POSIX ed il suo -prototipo è: +gruppi supplementari cui un utente può appartenere. Ogni processo può avere +almeno \const{NGROUPS\_MAX} gruppi supplementari\footnote{il numero massimo di + gruppi secondari può essere ottenuto con \func{sysconf} (vedi + sez.~\ref{sec:sys_sysconf}), leggendo il parametro + \texttt{\_SC\_NGROUPS\_MAX}.} in aggiunta al gruppo primario; questi vengono +ereditati dal processo padre e possono essere cambiati con queste funzioni. + +La funzione che permette di leggere i gruppi supplementari associati ad un +processo è \funcd{getgroups}; questa funzione è definita nello standard +POSIX.1, ed il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{unistd.h} @@ -1807,7 +1775,7 @@ specifica un valore di \param{size} uguale a 0 \param{list} non viene modificato, ma si ottiene il numero di gruppi supplementari. Una seconda funzione, \funcd{getgrouplist}, può invece essere usata per -ottenere tutti i gruppi a cui appartiene un utente; il suo prototipo è: +ottenere tutti i gruppi a cui appartiene un certo utente; il suo prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{grp.h} @@ -1819,12 +1787,12 @@ ottenere tutti i gruppi a cui appartiene un utente; il suo prototipo restituisce 0 in caso di successo e -1 in caso di fallimento.} \end{functions} -La funzione legge i gruppi supplementari dell'utente \param{user} eseguendo -una scansione del database dei gruppi (si veda \secref{sec:sys_user_group}) e -ritorna in \param{groups} la lista di quelli a cui l'utente appartiene. Si -noti che \param{ngroups} è passato come puntatore perché qualora il valore -specificato sia troppo piccolo la funzione ritorna -1, passando indietro il -numero dei gruppi trovati. +La funzione legge i gruppi supplementari dell'utente specificato da +\param{user}, eseguendo una scansione del database dei gruppi (si veda +sez.~\ref{sec:sys_user_group}). Ritorna poi in \param{groups} la lista di +quelli a cui l'utente appartiene. Si noti che \param{ngroups} è passato come +puntatore perché, qualora il valore specificato sia troppo piccolo, la +funzione ritorna -1, passando indietro il numero dei gruppi trovati. Per impostare i gruppi supplementari di un processo ci sono due funzioni, che possono essere usate solo se si hanno i privilegi di amministratore. La prima @@ -1851,7 +1819,7 @@ La funzione imposta i gruppi supplementari del processo corrente ai valori specificati nel vettore passato con l'argomento \param{list}, di dimensioni date dall'argomento \param{size}. Il numero massimo di gruppi supplementari è un parametro di sistema, che può essere ricavato con le modalità spiegate in -\secref{sec:sys_characteristics}. +sez.~\ref{sec:sys_characteristics}. Se invece si vogliono impostare i gruppi supplementari del processo a quelli di un utente specifico, si può usare \funcd{initgroups} il cui prototipo è: @@ -1876,7 +1844,21 @@ con cui costruisce una lista di gruppi supplementari, a cui aggiunge anche \func{setgroups}. Si tenga presente che sia \func{setgroups} che \func{initgroups} non sono definite nello standard POSIX.1 e che pertanto non è possibile utilizzarle quando si definisce \macro{\_POSIX\_SOURCE} o si -compila con il flag \cmd{-ansi}. +compila con il flag \cmd{-ansi}, è pertanto meglio evitarle se si vuole +scrivere codice portabile. + + +% +% Da fare !!! +% insieme alla risistemazioni dei titoli delle sezioni precedenti +% (accorpare il materiale) qualosa tipo: +% le funzioni di controllo +% estenzioni di Linux +% +%\subsection{La gestione delle capabilities} +%\label{sec:proc_capabilities} + + \section{La gestione della priorità di esecuzione} @@ -1903,7 +1885,7 @@ cosiddetto \textit{prehemptive multitasking}: questo significa che al contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative multitasking}) non sono i singoli processi, ma il kernel stesso a decidere quando la CPU deve essere passata ad un altro processo. Come accennato in -\secref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione +sez.~\ref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione apposita del kernel, lo \textit{scheduler}\index{scheduler}, il cui scopo è quello di distribuire al meglio il tempo di CPU fra i vari processi. @@ -1928,7 +1910,7 @@ kernel provvedere a mettere in esecuzione un altro processo. Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del processo, in Linux un processo può trovarsi in uno degli stati riportati in -\tabref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato +tab.~\ref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato \textit{runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque sia la sua priorità, un processo non potrà mai essere messo in esecuzione fintanto che esso si trova in uno qualunque degli altri stati. @@ -1944,7 +1926,7 @@ fintanto che esso si trova in uno qualunque degli altri stati. \textbf{Runnable}& \texttt{R} & Il processo è in esecuzione o è pronto ad essere eseguito (cioè è in attesa che gli venga assegnata la CPU). \\ - \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un + \textbf{Sleep} & \texttt{S} & Il processo è in attesa di un risposta dal sistema, ma può essere interrotto da un segnale. \\ \textbf{Uninterrutible Sleep}& \texttt{D} & Il processo è in @@ -1972,12 +1954,12 @@ non abbia risultati significativi in termini di prestazioni. Il meccanismo tradizionale di scheduling di Unix (che tratteremo in -\secref{sec:proc_sched_stand}) è sempre stato basato su delle \textsl{priorità - dinamiche}, in modo da assicurare che tutti i processi, anche i meno -importanti, possano ricevere un po' di tempo di CPU. In sostanza quando un -processo ottiene la CPU la sua priorità viene diminuita. In questo modo alla -fine, anche un processo con priorità iniziale molto bassa, finisce per avere -una priorità sufficiente per essere eseguito. +sez.~\ref{sec:proc_sched_stand}) è sempre stato basato su delle +\textsl{priorità dinamiche}, in modo da assicurare che tutti i processi, anche +i meno importanti, possano ricevere un po' di tempo di CPU. In sostanza quando +un processo ottiene la CPU la sua priorità viene diminuita. In questo modo +alla fine, anche un processo con priorità iniziale molto bassa, finisce per +avere una priorità sufficiente per essere eseguito. Lo standard POSIX.1b però ha introdotto il concetto di \textsl{priorità assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione @@ -1998,7 +1980,7 @@ Ovviamente questo avviene solo per i processi che sono pronti per essere eseguiti (cioè nello stato \textit{runnable}). La priorità assoluta viene in genere indicata con un numero intero, ed un valore più alto comporta una priorità maggiore. Su questa politica di scheduling torneremo in -\secref{sec:proc_real_time}. +sez.~\ref{sec:proc_real_time}. In generale quello che succede in tutti gli Unix moderni è che ai processi normali viene sempre data una priorità assoluta pari a zero, e la decisione di @@ -2026,7 +2008,7 @@ essere eseguito, e quando un processo potr nell'esecuzione. Il meccanismo usato da Linux è piuttosto semplice, ad ogni processo è -assegnata una \textit{time-slice}, cioè in intervallo di tempo (letteralmente +assegnata una \textit{time-slice}, cioè un 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 @@ -2036,13 +2018,13 @@ 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\index{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 +Durante la sua esecuzione lo scheduler\index{scheduler} scandisce la coda dei +processi in stato \textit{runnable} associando, in base al valore di +\var{counter}, un peso ad ogni 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 + multiprocessore viene favorito un processo 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 @@ -2050,13 +2032,13 @@ verranno messi in esecuzione. La priorità di un processo è così controllata attraverso il valore di \var{nice}, che stabilisce la durata della \textit{time-slice}; per il -meccanismo appena descritto infatti un valore più lungo infatti assicura una -maggiore attribuzione di CPU. L'origine del nome di questo parametro sta nel -fatto che 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 è: +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 è: \begin{prototype}{unistd.h} {int nice(int inc)} Aumenta il valore di \var{nice} per il processo corrente. @@ -2095,15 +2077,16 @@ Restituisce il valore di \var{nice} per l'insieme dei processi specificati. \item[\errcode{EINVAL}] il valore di \param{which} non è valido. \end{errlist}} \end{prototype} -\noindent (in vecchie versioni può essere necessario includere anche +\noindent nelle vecchie versioni può essere necessario includere anche \file{}, questo non è più necessario con versioni recenti delle -librerie, ma è comunque utile per portabilità). +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. +La funzione permette, a seconda del valore di \param{which}, di leggere la +priorità di un processo, di un gruppo di processi (vedi +sez.~\ref{sec:sess_proc_group}) o di un utente, specificando un corrispondente +valore per \param{who} secondo la legenda di tab.~\ref{tab:proc_getpriority}; +un valore nullo di quest'ultimo indica il processo, il gruppo di processi o +l'utente correnti. \begin{table}[htb] \centering @@ -2163,41 +2146,40 @@ Ultrix, *BSD) la corrispondenza pu \subsection{Il meccanismo di \textit{scheduling real-time}} \label{sec:proc_real_time} -Come spiegato in \secref{sec:proc_sched} lo standard POSIX.1b ha introdotto le -priorità assolute per permettere la gestione di processi real-time. In realtà -nel caso di Linux non si tratta di un vero hard real-time, in quanto in +Come spiegato in sez.~\ref{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, RTAI o Adeos, con i quali è possibile ottenere un sistema effettivamente hard real-time. In tal caso infatti gli interrupt vengono intercettati dall'interfaccia real-time (o nel caso di - Adeos gestiti dalle code del nano-kernel), in modo da poterlo controllare + Adeos gestiti dalle code del nano-kernel), in modo da poterli controllare 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\index{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 +controllo della memoria virtuale (vedi sez.~\ref{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. +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\index{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 vengono tenuti in una coda -tocca al kernel decidere quale deve essere eseguito. - +e 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{2cm}\desclabelstyle{\nextlinelabel}} +\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}} \item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito fintanto che non cede volontariamente la CPU, si blocca, finisce o viene interrotto da un processo a priorità più alta. @@ -2221,18 +2203,17 @@ prototipo \item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il relativo valore di \param{p} non è valido. \item[\errcode{EPERM}] il processo non ha i privilegi per attivare la - politica richiesta (vale solo per \const{SCHED\_FIFO} e - \const{SCHED\_RR}). + politica richiesta. \end{errlist}} \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. -Solo un processo con i privilegi di amministratore può impostare 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. +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 può impostare priorità +assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}. \begin{table}[htb] \centering @@ -2254,20 +2235,16 @@ la politica di scheduling corrente. \end{table} Il valore della priorità è passato attraverso la struttura -\struct{sched\_param} (riportata in \figref{fig:sig_sched_param}), il cui solo -campo attualmente definito è \var{sched\_priority}, che nel caso delle +\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 zero è legale, ma indica i processi normali). -\begin{figure}[!htb] +\begin{figure}[!bht] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct sched_param { - int sched_priority; -}; - \end{lstlisting} + \includestruct{listati/sched_param.c} \end{minipage} \normalsize \caption{La struttura \structd{sched\_param}.} @@ -2291,7 +2268,7 @@ e \funcd{sched\_get\_priority\_min}, i cui prototipi sono: \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[\errcode{EINVAL}] il valore di \param{policy} è invalido. + \item[\errcode{EINVAL}] il valore di \param{policy} non è valido. \end{errlist}} \end{functions} @@ -2326,8 +2303,8 @@ La priorit \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 +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. @@ -2340,7 +2317,6 @@ prototipi sono: \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)} Imposta 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}. @@ -2377,7 +2353,7 @@ il suo prototipo La funzione restituisce il valore dell'intervallo di tempo usato per la politica \textit{round robin} in una struttura \struct{timespec}, (la cui -definizione si può trovare in \figref{fig:sys_timeval_struct}). +definizione si può trovare in fig.~\ref{fig:sys_timeval_struct}). Come accennato ogni processo che usa lo scheduling real-time può rilasciare @@ -2429,14 +2405,14 @@ essere interrotto in qualunque momento dal kernel che mette in esecuzione un altro processo o dalla ricezione di un segnale; occorre pertanto essere accorti nei confronti delle possibili \textit{race condition}\index{race condition} (vedi -\secref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase in -cui non erano ancora state completate. +sez.~\ref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase +in cui non erano ancora state completate. Nel caso dell'interazione fra processi la situazione è molto più semplice, ed occorre preoccuparsi della atomicità delle operazioni solo quando si ha a che fare con meccanismi di intercomunicazione (che esamineremo in dettaglio in -\capref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in -\secref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate +cap.~\ref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in +sez.~\ref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate funzioni di libreria per compiere le operazioni necessarie è garanzia sufficiente di atomicità in quanto le system call con cui esse sono realizzate non possono essere interrotte (o subire interferenze pericolose) da altri @@ -2448,7 +2424,7 @@ qualunque momento, e le operazioni di un eventuale \textit{signal handler} sono compiute nello stesso spazio di indirizzi del processo. Per questo, anche il solo accesso o l'assegnazione di una variabile possono non essere più operazioni atomiche (torneremo su questi aspetti in -\secref{sec:sig_control}). +sez.~\ref{sec:sig_control}). In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t}, il cui accesso è assicurato essere atomico. In pratica comunque si può @@ -2475,7 +2451,7 @@ processo che accede alla stessa risorsa quando ancora non tutti i passi sono stati completati. Dato che in un sistema multitasking ogni processo può essere interrotto in -qualunque momento per farne subentrare un'altro in esecuzione, niente può +qualunque momento per farne subentrare un altro in esecuzione, niente può assicurare un preciso ordine di esecuzione fra processi diversi o che una sezione di un programma possa essere eseguita senza interruzioni da parte di altri. Queste situazioni comportano pertanto errori estremamente subdoli e @@ -2492,7 +2468,7 @@ di eseguire atomicamente le operazioni necessarie, occorre che quelle parti di codice in cui si compiono le operazioni sulle risorse condivise (le cosiddette \textsl{sezioni critiche}\index{sezioni critiche}) del programma, siano opportunamente protette da meccanismi di sincronizzazione (torneremo su queste -problematiche di questo tipo in \capref{cha:IPC}). +problematiche di questo tipo in cap.~\ref{cha:IPC}). Un caso particolare di \textit{race condition}\index{race condition} sono poi i cosiddetti \textit{deadlock}\index{deadlock}, particolarmente gravi in @@ -2513,7 +2489,7 @@ accorgessimo proprio fra il controllo e la messa in attesa, quest'ultima diventerà perpetua (da cui il nome di \textit{deadlock}\index{deadlock}). In tutti questi casi è di fondamentale importanza il concetto di atomicità -visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere +visto in sez.~\ref{sec:proc_atom_oper}; questi problemi infatti possono essere risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile eseguire in maniera atomica le operazioni necessarie.