\item \errcode{EPERM} \textit{Operation not permitted}. L'operazione non è
permessa: solo il proprietario del file o un processo con sufficienti
privilegi può eseguire l'operazione.
-\item \errcode{ENOENT} \textit{No such file or directory}. Il file indicato dal
- pathname non esiste: o una delle componenti non esiste o il pathname
- contiene un link simbolico spezzato. Errore tipico di un riferimento ad un
- file che si suppone erroneamente essere esistente.
+\item \errcode{ENOENT} \textit{No such file or directory}. Il file indicato
+ dal \index{\textit{pathname}}\textit{pathname} non esiste: o una delle
+ componenti non esiste o il \textit{pathname} contiene un link simbolico
+ spezzato. Errore tipico di un riferimento ad un file che si suppone
+ erroneamente essere esistente.
\item \errcode{EIO} \textit{Input/output error}. Errore di input/output: usato
per riportare errori hardware in lettura/scrittura su un dispositivo.
\item \errcode{ENXIO} \textit{No such device or address}. Dispositivo
al file non è consentito: i permessi del file o della directory non
consentono l'operazione.
\item \errcode{ELOOP} \textit{Too many symbolic links encountered}. Ci sono
- troppi link simbolici nella risoluzione di un pathname.
+ troppi link simbolici nella risoluzione di un
+ \index{\textit{pathname}}\textit{pathname}.
\item \errcode{ENAMETOOLONG} \textit{File name too long}. Si è indicato un
- pathname troppo lungo.
+ \textit{pathname} troppo lungo.
\item \errcode{ENOTBLK} \textit{Block device required}. Si è specificato un
file che non è un \textit{block device} in un contesto in cui era necessario
specificare un \textit{block device} (ad esempio si è tentato di montare un
\item \errcode{ENOMEM} \textit{No memory available}. Il kernel non è in grado
di allocare ulteriore memoria per completare l'operazione richiesta.
\item \errcode{EDEADLK} \textit{Deadlock avoided}. L'allocazione di una
- risorsa avrebbe causato un \textit{deadlock}\index{deadlock}. Non sempre il
- sistema è in grado di riconoscere queste situazioni, nel qual caso si
- avrebbe in blocco.
+ risorsa avrebbe causato un \textit{deadlock}\index{\textit{deadlock}}. Non
+ sempre il sistema è in grado di riconoscere queste situazioni, nel qual caso
+ si avrebbe il blocco.
\item \errcode{EFAULT} \textit{Bad address}. Una stringa passata come parametro
è fuori dello spazio di indirizzi del processo, in genere questa situazione
provoca l'emissione di un segnale di \textit{segment violation}
\label{sec:file_noblocking}
Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
-\textit{fast} e \textit{slow} system call,\index{system call lente} che in
+\textit{fast} e \textit{slow} system call,\index{system~call~lente} che in
certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
ricordi però che questo può accadere solo per le pipe, i
- socket\index{socket} ed alcuni file di dispositivo\index{file!di
- dispositivo}; sui file normali le funzioni di lettura e scrittura
- ritornano sempre subito.} Ad esempio le operazioni di lettura possono
-bloccarsi quando non ci sono dati disponibili sul descrittore su cui si sta
-operando.
+ socket\index{socket} ed alcuni file di
+ dispositivo\index{file!di~dispositivo}; sui file normali le funzioni di
+ lettura e scrittura ritornano sempre subito.} Ad esempio le operazioni di
+lettura possono bloccarsi quando non ci sono dati disponibili sul descrittore
+su cui si sta operando.
Questo comportamento causa uno dei problemi più comuni che ci si trova ad
affrontare nelle operazioni di I/O, che si verifica quando si deve operare con
ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
-potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}.
+potrebbe addirittura arrivare ad un \textit{deadlock}\index{\textit{deadlock}}.
Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
questo tipo di comportamento delle funzioni di I/O aprendo un file in
restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa modalità di I/O
permette di risolvere il problema controllando a turno i vari file descriptor,
in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
-Ovviamente questa tecnica, detta \textit{polling}\index{polling}, è
+Ovviamente questa tecnica, detta \textit{polling}\index{\textit{polling}}, è
estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
eseguire in continuazione delle system call che nella gran parte dei casi
falliranno.
\param{exceptfds}), non diventa attivo, per un tempo massimo specificato da
\param{timeout}.
+\index{\textit{file~descriptor~set}|(}
Per specificare quali file descriptor si intende \textsl{selezionare}, la
funzione usa un particolare oggetto, il \textit{file descriptor set},
identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di
-file descriptor, in maniera analoga a come un
-\index{\textit{signal set}}\textit{signal set} (vedi
+file descriptor, in maniera analoga a come un
+\index{\textit{signal~set}}\textit{signal set} (vedi
sez.~\ref{sec:sig_sigset}) identifica un insieme di segnali. Per la
manipolazione di questi \textit{file descriptor set} si possono usare delle
opportune macro di preprocessore:
specificare anche un tempo nullo (cioè una struttura \struct{timeval} con i
campi impostati a zero), qualora si voglia semplicemente controllare lo stato
corrente dei file descriptor.
+\index{\textit{file~descriptor~set}|)}
La funzione restituisce il numero di file descriptor pronti,\footnote{questo è
il comportamento previsto dallo standard, ma la standardizzazione della
funzione.
L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
-race condition\index{race condition} quando ci si deve porre in attesa sia di
-un segnale che di dati. La tecnica classica è quella di utilizzare il gestore
-per impostare una variabile globale e controllare questa nel corpo principale
-del programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci
-spazio a possibili race condition, per cui diventa essenziale utilizzare
-\func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire
-il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde
-evitare l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe
-perso.
+race condition\index{\textit{race~condition}} quando ci si deve porre in
+attesa sia di un segnale che di dati. La tecnica classica è quella di
+utilizzare il gestore per impostare una variabile globale e controllare questa
+nel corpo principale del programma; abbiamo visto in
+sez.~\ref{sec:sig_example} come questo lasci spazio a possibili race
+condition, per cui diventa essenziale utilizzare \func{sigprocmask} per
+disabilitare la ricezione del segnale prima di eseguire il controllo e
+riabilitarlo dopo l'esecuzione delle relative operazioni, onde evitare
+l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe perso.
Nel nostro caso il problema si pone quando oltre al segnale si devono tenere
sotto controllo anche dei file descriptor con \func{select}, in questo caso si
e si potrebbero eseguire di conseguenza le operazioni relative al segnale e
alla gestione dati con un ciclo del tipo:
\includecodesnip{listati/select_race.c} qui però emerge una race
-condition,\index{race condition} perché se il segnale arriva prima della
-chiamata a \func{select}, questa non verrà interrotta, e la ricezione del
-segnale non sarà rilevata.
+condition,\index{\textit{race~condition}} perché se il segnale arriva prima
+della chiamata a \func{select}, questa non verrà interrotta, e la ricezione
+del segnale non sarà rilevata.
Per questo è stata introdotta \func{pselect} che attraverso l'argomento
\param{sigmask} permette di riabilitare la ricezione il segnale
Benché la modalità di apertura asincrona di un file possa risultare utile in
varie occasioni (in particolar modo con i socket\index{socket} e gli altri
-file per i quali le funzioni di I/O sono \index{system call lente}system call
+file per i quali le funzioni di I/O sono \index{system~call~lente}system call
lente), essa è comunque limitata alla notifica della disponibilità del file
descriptor per le operazioni di I/O, e non ad uno svolgimento asincrono delle
medesime. Lo standard POSIX.1b definisce una interfaccia apposita per l'I/O
illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del file viene
riportata direttamente nello spazio degli indirizzi del programma. Tutte le
operazioni su questa zona verranno riportate indietro sul file dal meccanismo
-della memoria virtuale\index{memoria virtuale} che trasferirà il contenuto di
+della memoria virtuale\index{memoria~virtuale} che trasferirà il contenuto di
quel segmento sul file invece che nella swap, per cui si può parlare tanto di
file mappato in memoria, quanto di memoria mappata su file.
istante.
Infatti, dato che l'accesso è fatto direttamente attraverso la memoria
-virtuale,\index{memoria virtuale} la sezione di memoria mappata su cui si
+virtuale,\index{memoria~virtuale} la sezione di memoria mappata su cui si
opera sarà a sua volta letta o scritta sul file una pagina alla volta e solo
per le parti effettivamente usate, il tutto in maniera completamente
trasparente al processo; l'accesso alle pagine non ancora caricate avverrà
riportati sul file. Ne viene fatta una copia
privata cui solo il processo chiamante ha
accesso. Le modifiche sono mantenute attraverso
- il meccanismo del
- \textit{copy on write}\index{copy on write} e
+ il meccanismo del \textit{copy on
+ write}\index{\textit{copy~on~write}} e
salvate su swap in caso di necessità. Non è
specificato se i cambiamenti sul file originale
vengano riportati sulla regione
dovevano fallire con \errcode{ETXTBSY}).\\
\const{MAP\_EXECUTABLE}& Ignorato. \\
\const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
- delle pagine di swap ad uso del meccanismo di
- \textit{copy on write}\index{copy on write}
+ delle pagine di swap ad uso del meccanismo del
+ \textit{copy on
+ write}\index{\textit{copy~on~write}}
per mantenere le
modifiche fatte alla regione mappata, in
questo caso dopo una scrittura, se non c'è più
Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
piuttosto complessi, essi si possono comprendere solo tenendo presente che
tutto quanto è comunque basato sul basato sul meccanismo della memoria
-virtuale.\index{memoria virtuale} Questo comporta allora una serie di
+virtuale.\index{memoria~virtuale} Questo comporta allora una serie di
conseguenze. La più ovvia è che se si cerca di scrivere su una zona mappata in
sola lettura si avrà l'emissione di un segnale di violazione di accesso
(\const{SIGSEGV}), dato che i permessi sul segmento di memoria relativo non
o in corrispondenza di una eventuale \func{msync}.
Dato per i file mappati in memoria le operazioni di I/O sono gestite
-direttamente dalla memoria virtuale, occorre essere consapevoli delle
-interazioni che possono esserci con operazioni effettuate con l'interfaccia
-standard dei file di cap.~\ref{cha:file_unix_interface}. Il problema è che una
-volta che si è mappato un file, le operazioni di lettura e scrittura saranno
-eseguite sulla memoria, e riportate su disco in maniera autonoma dal sistema
-della memoria virtuale.
+direttamente dalla \index{memoria~virtuale}memoria virtuale, occorre essere
+consapevoli delle interazioni che possono esserci con operazioni effettuate
+con l'interfaccia standard dei file di cap.~\ref{cha:file_unix_interface}. Il
+problema è che una volta che si è mappato un file, le operazioni di lettura e
+scrittura saranno eseguite sulla memoria, e riportate su disco in maniera
+autonoma dal sistema della memoria virtuale.
Pertanto se si modifica un file con l'interfaccia standard queste modifiche
potranno essere visibili o meno a seconda del momento in cui la memoria
in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
stesso file non è possibile determinare la sequenza in cui essi opereranno.
-Questo causa la possibilità di race condition\index{race condition}; in
-generale le situazioni più comuni sono due: l'interazione fra un processo che
-scrive e altri che leggono, in cui questi ultimi possono leggere informazioni
-scritte solo in maniera parziale o incompleta; o quella in cui diversi
-processi scrivono, mescolando in maniera imprevedibile il loro output sul
-file.
+Questo causa la possibilità di race condition\index{\textit{race~condition}};
+in generale le situazioni più comuni sono due: l'interazione fra un processo
+che scrive e altri che leggono, in cui questi ultimi possono leggere
+informazioni scritte solo in maniera parziale o incompleta; o quella in cui
+diversi processi scrivono, mescolando in maniera imprevedibile il loro output
+sul file.
In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le race condition\index{race condition}, attraverso una serie di
-funzioni che permettono di bloccare l'accesso al file da parte di altri
+evitare le race condition\index{\textit{race~condition}}, attraverso una serie
+di funzioni che permettono di bloccare l'accesso al file da parte di altri
processi, così da evitare le sovrapposizioni, e garantire la atomicità delle
operazioni di scrittura.
\item[\errcode{EDEADLK}] Si è richiesto un lock su una regione bloccata da
un altro processo che è a sua volta in attesa dello sblocco di un lock
mantenuto dal processo corrente; si avrebbe pertanto un
- \textit{deadlock}\index{deadlock}. Non è garantito che il sistema
- riconosca sempre questa situazione.
+ \textit{deadlock}\index{\textit{deadlock}}. Non è garantito che il
+ sistema riconosca sempre questa situazione.
\item[\errcode{EINTR}] La funzione è stata interrotta da un segnale prima
di poter acquisire un lock.
\end{errlist}
\begin{figure}[htb]
\centering \includegraphics[width=9cm]{img/file_lock_dead}
- \caption{Schema di una situazione di \textit{deadlock}\index{deadlock}.}
+ \caption{Schema di una situazione di
+ \textit{deadlock}\index{\textit{deadlock}}.}
\label{fig:file_flock_dead}
\end{figure}
del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
rilasci il blocco. Ma cosa accade se il processo 2 nel frattempo tenta a sua
volta di ottenere un lock sulla regione A? Questa è una tipica situazione che
-porta ad un \textit{deadlock}\index{deadlock}, dato che a quel punto anche il
-processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo. Per
-questo motivo il kernel si incarica di rilevare situazioni di questo tipo, ed
-impedirle restituendo un errore di \errcode{EDEADLK} alla funzione che cerca
-di acquisire un lock che porterebbe ad un \textit{deadlock}.
+porta ad un \textit{deadlock}\index{\textit{deadlock}}, dato che a quel punto
+anche il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro
+processo. Per questo motivo il kernel si incarica di rilevare situazioni di
+questo tipo, ed impedirle restituendo un errore di \errcode{EDEADLK} alla
+funzione che cerca di acquisire un lock che porterebbe ad un
+\textit{deadlock}.
\begin{figure}[!bht]
\centering \includegraphics[width=13cm]{img/file_posix_lock}
\errval{ENOSPC}, \errval{EIO}.}
\end{prototype}
-La funzione crea sul pathname \param{newpath} un collegamento diretto al file
-indicato da \param{oldpath}. Per quanto detto la creazione di un nuovo
-collegamento diretto non copia il contenuto del file, ma si limita a creare
-una voce nella directory specificata da \param{newpath} e ad aumentare di uno
-il numero di riferimenti al file (riportato nel campo \var{st\_nlink} della
-struttura \struct{stat}, vedi sez.~\ref{sec:file_stat}) aggiungendo il nuovo
-nome ai precedenti. Si noti che uno stesso file può essere così chiamato con
-vari nomi in diverse directory.
+La funzione crea sul \index{\textit{pathname}}\textit{pathname}
+\param{newpath} un collegamento diretto al file indicato da \param{oldpath}.
+Per quanto detto la creazione di un nuovo collegamento diretto non copia il
+contenuto del file, ma si limita a creare una voce nella directory specificata
+da \param{newpath} e ad aumentare di uno il numero di riferimenti al file
+(riportato nel campo \var{st\_nlink} della struttura \struct{stat}, vedi
+sez.~\ref{sec:file_stat}) aggiungendo il nuovo nome ai precedenti. Si noti che
+uno stesso file può essere così chiamato con vari nomi in diverse directory.
Per quanto dicevamo in sez.~\ref{sec:file_filesystem} la creazione di un
-collegamento diretto è possibile solo se entrambi i pathname sono nello stesso
-filesystem; inoltre il filesystem deve supportare i collegamenti diretti (il
-meccanismo non è disponibile ad esempio con il filesystem \acr{vfat} di
-Windows).
+collegamento diretto è possibile solo se entrambi i
+\index{\textit{pathname}}\textit{pathname} sono nello stesso filesystem;
+inoltre il filesystem deve supportare i collegamenti diretti (il meccanismo
+non è disponibile ad esempio con il filesystem \acr{vfat} di Windows).
La funzione inoltre opera sia sui file ordinari che sugli altri oggetti del
filesystem, con l'eccezione delle directory. In alcune versioni di Unix solo
La funzione cancella il nome specificato da \param{pathname} nella relativa
directory e decrementa il numero di riferimenti nel relativo
inode\index{inode}. Nel caso di link simbolico cancella il link simbolico; nel
-caso di socket\index{socket}, fifo o file di dispositivo\index{file!di
- dispositivo} rimuove il nome, ma come per i file i processi che hanno aperto
-uno di questi oggetti possono continuare ad utilizzarlo.
+caso di socket\index{socket}, fifo o file di
+dispositivo\index{file!di~dispositivo} rimuove il nome, ma come per i file i
+processi che hanno aperto uno di questi oggetti possono continuare ad
+utilizzarlo.
Per cancellare una voce in una directory è necessario avere il permesso di
scrittura su di essa, dato che si va a rimuovere una voce dal suo contenuto, e
\item[\errcode{EINVAL}] \param{newpath} contiene un prefisso di
\param{oldpath} o più in generale si è cercato di creare una directory come
sotto-directory di se stessa.
- \item[\errcode{ENOTDIR}] Uno dei componenti dei pathname non è una directory
- o \param{oldpath} è una directory e \param{newpath} esiste e non è una
+ \item[\errcode{ENOTDIR}] Uno dei componenti dei
+ \index{\textit{pathname}}\textit{pathname} non è una directory o
+ \param{oldpath} è una directory e \param{newpath} esiste e non è una
directory.
\end{errlist}
ed inoltre \errval{EACCES}, \errval{EPERM}, \errval{EMLINK},
fig.~\ref{fig:file_link_loop} è un usato per poter permettere a \cmd{grub}
(un bootloader in grado di leggere direttamente da vari filesystem il file
da lanciare come sistema operativo) di vedere i file contenuti nella
- directory \file{/boot} con lo stesso pathname con cui verrebbero visti dal
- sistema operativo, anche se essi si trovano, come accade spesso, su una
- partizione separata (che \cmd{grub}, all'avvio, vede come radice).}
+ directory \file{/boot} con lo stesso \textit{pathname} con cui verrebbero
+ visti dal sistema operativo, anche se essi si trovano, come accade spesso,
+ su una partizione separata (che \cmd{grub}, all'avvio, vede come radice).}
Questo può causare problemi per tutti quei programmi che effettuano la
scansione di una directory senza tener conto dei link simbolici, ad esempio se
\file{/boot/boot/boot} e così via.
Per questo motivo il kernel e le librerie prevedono che nella risoluzione di
-un pathname possano essere seguiti un numero limitato di link simbolici, il
-cui valore limite è specificato dalla costante \const{MAXSYMLINKS}. Qualora
-questo limite venga superato viene generato un errore ed \var{errno} viene
-impostata al valore \errcode{ELOOP}.
+un \index{\textit{pathname}}\textit{pathname} possano essere seguiti un numero
+limitato di link simbolici, il cui valore limite è specificato dalla costante
+\const{MAXSYMLINKS}. Qualora questo limite venga superato viene generato un
+errore ed \var{errno} viene impostata al valore \errcode{ELOOP}.
Un punto da tenere sempre presente è che, come abbiamo accennato, un link
simbolico può fare riferimento anche ad un file che non esiste; ad esempio
La funzione crea una nuova directory vuota, che contiene cioè solo le due voci
standard (\file{.} e \file{..}), con il nome indicato dall'argomento
-\param{dirname}. Il nome può essere indicato sia come pathname assoluto che
-relativo.
+\param{dirname}. Il nome può essere indicato sia come
+\index{\textit{pathname}}\textit{pathname} assoluto che relativo.
I permessi di accesso alla directory (vedi sez.~\ref{sec:file_access_control})
sono specificati da \param{mode}, i cui possibili valori sono riportati in
La funzione cancella la directory \param{dirname}, che deve essere vuota (la
directory deve cioè contenere soltanto le due voci standard \file{.} e
-\file{..}). Il nome può essere indicato con il pathname assoluto o relativo.
+\file{..}). Il nome può essere indicato con il
+\index{\textit{pathname}}\textit{pathname} assoluto o relativo.
La modalità con cui avviene la cancellazione è analoga a quella di
\func{unlink}: fintanto che il numero di link all'inode\index{inode} della
Finora abbiamo parlato esclusivamente di file, directory e link simbolici; in
sez.~\ref{sec:file_file_types} abbiamo visto però che il sistema prevede pure
-degli altri tipi di file speciali, come i file di dispositivo
-\index{file!di dispositivo}
-e le fifo (i socket\index{socket} sono un caso a parte, che
-vedremo in cap.~\ref{cha:socket_intro}).
+degli altri tipi di file speciali, come i file di dispositivo
+\index{file!di~dispositivo} e le fifo (i socket\index{socket} sono un caso a
+parte, che vedremo in cap.~\ref{cha:socket_intro}).
La manipolazione delle caratteristiche di questi file e la loro cancellazione
può essere effettuata con le stesse funzioni che operano sui file regolari; ma
A ciascun processo è associata una directory nel filesystem che è chiamata
\textsl{directory corrente} o \textsl{directory di lavoro} (in inglese
\textit{current working directory}) che è quella a cui si fa riferimento
-quando un pathname è espresso in forma relativa, dove il ``\textsl{relativa}''
-fa riferimento appunto a questa directory.
+quando un \index{\textit{pathname}}\textit{pathname} è espresso in forma
+relativa, dove il ``\textsl{relativa}'' fa riferimento appunto a questa
+directory.
Quando un utente effettua il login, questa directory viene impostata alla
\textit{home directory} del suo account. Il comando \cmd{cd} della shell
directory corrente di qualunque comando da essa lanciato.
In genere il kernel tiene traccia per ciascun processo dell'inode\index{inode}
-della directory di lavoro, per ottenere il pathname occorre usare una apposita
-funzione di libreria, \funcd{getcwd}, il cui prototipo è:
+della directory di lavoro, per ottenere il
+\index{\textit{pathname}}\textit{pathname} occorre usare una apposita funzione
+di libreria, \funcd{getcwd}, il cui prototipo è:
\begin{prototype}{unistd.h}{char *getcwd(char *buffer, size\_t size)}
- Legge il pathname della directory di lavoro corrente.
+ Legge il \textit{pathname} della directory di lavoro corrente.
\bodydesc{La funzione restituisce il puntatore \param{buffer} se riesce,
\val{NULL} se fallisce, in quest'ultimo caso la variabile
\item[\errcode{EINVAL}] L'argomento \param{size} è zero e \param{buffer} non
è nullo.
\item[\errcode{ERANGE}] L'argomento \param{size} è più piccolo della
- lunghezza del pathname.
+ lunghezza del \textit{pathname}.
\item[\errcode{EACCES}] Manca il permesso di lettura o di ricerca su uno dei
- componenti del pathname (cioè su una delle directory superiori alla
- corrente).
+ componenti del \textit{pathname} (cioè su una delle directory superiori
+ alla corrente).
\end{errlist}}
\end{prototype}
-La funzione restituisce il pathname completo della directory di lavoro nella
-stringa puntata da \param{buffer}, che deve essere precedentemente allocata,
-per una dimensione massima di \param{size}. Il buffer deve essere
-sufficientemente lungo da poter contenere il pathname completo più lo zero di
-terminazione della stringa. Qualora esso ecceda le dimensioni specificate con
-\param{size} la funzione restituisce un errore.
+La funzione restituisce il \index{\textit{pathname}}\textit{pathname} completo
+della directory di lavoro nella stringa puntata da \param{buffer}, che deve
+essere precedentemente allocata, per una dimensione massima di \param{size}.
+Il buffer deve essere sufficientemente lungo da poter contenere il
+\textit{pathname} completo più lo zero di terminazione della stringa. Qualora
+esso ecceda le dimensioni specificate con \param{size} la funzione restituisce
+un errore.
Si può anche specificare un puntatore nullo come
\param{buffer},\footnote{questa è un'estensione allo standard POSIX.1,
supportata da Linux.} nel qual caso la stringa sarà allocata automaticamente
per una dimensione pari a \param{size} qualora questa sia diversa da zero, o
-della lunghezza esatta del pathname altrimenti. In questo caso ci si deve
-ricordare di disallocare la stringa una volta cessato il suo utilizzo.
+della lunghezza esatta del \index{\textit{pathname}}\textit{pathname}
+altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una
+volta cessato il suo utilizzo.
Di questa funzione esiste una versione \code{char *getwd(char *buffer)} fatta
per compatibilità all'indietro con BSD, che non consente di specificare la
dimensione del buffer; esso deve essere allocato in precedenza ed avere una
dimensione superiore a \const{PATH\_MAX} (di solito 256 byte, vedi
sez.~\ref{sec:sys_limits}); il problema è che in Linux non esiste una
-dimensione superiore per un pathname, per cui non è detto che il buffer sia
-sufficiente a contenere il nome del file, e questa è la ragione principale per
-cui questa funzione è deprecata.
+dimensione superiore per un \index{\textit{pathname}}\textit{pathname}, per
+cui non è detto che il buffer sia sufficiente a contenere il nome del file, e
+questa è la ragione principale per cui questa funzione è deprecata.
Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è
sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola
differenza che essa ritorna il valore della variabile di ambiente \val{PWD},
-che essendo costruita dalla shell può contenere un pathname comprendente anche
-dei link simbolici. Usando \func{getcwd} infatti, essendo il pathname ricavato
-risalendo all'indietro l'albero della directory, si perderebbe traccia di ogni
-passaggio attraverso eventuali link simbolici.
+che essendo costruita dalla shell può contenere un \textit{pathname}
+comprendente anche dei link simbolici. Usando \func{getcwd} infatti, essendo
+il \index{\textit{pathname}}\textit{pathname} ricavato risalendo all'indietro
+l'albero della directory, si perderebbe traccia di ogni passaggio attraverso
+eventuali link simbolici.
Per cambiare la directory di lavoro si può usare la funzione \funcd{chdir}
(equivalente del comando di shell \cmd{cd}) il cui nome sta appunto per
quale si hanno i permessi di accesso.
Dato che anche le directory sono file, è possibile riferirsi ad esse anche
-tramite il file descriptor, e non solo tramite il pathname, per fare questo si
-usa \funcd{fchdir}, il cui prototipo è:
+tramite il file descriptor, e non solo tramite il
+\index{\textit{pathname}}\textit{pathname}, per fare questo si usa
+\funcd{fchdir}, il cui prototipo è:
\begin{prototype}{unistd.h}{int fchdir(int fd)}
Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del
- pathname.
+ \textit{pathname}.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
errore, in caso di errore \var{errno} assumerà i valori \errval{EBADF} o
prima vista. Infatti anche se sembrerebbe banale generare un nome a caso e
creare il file dopo aver controllato che questo non esista, nel momento fra il
controllo e la creazione si ha giusto lo spazio per una possibile \textit{race
- condition}\index{race condition} (si ricordi quanto visto in
+ condition}\index{\textit{race~condition}} (si ricordi quanto visto in
sez.~\ref{sec:proc_race_cond}).
Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei,
standard non specifica in quale directory verrà aperto il file, ma le
\acr{glibc} prima tentano con \const{P\_tmpdir} e poi con \file{/tmp}. Questa
funzione è rientrante e non soffre di problemi di \textit{race
- condition}\index{race condition}.
+ condition}\index{\textit{race~condition}}.
Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo
caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che
\end{prototype}
\noindent dato che \param{template} deve poter essere modificata dalla
funzione non si può usare una stringa costante. Tutte le avvertenze riguardo
-alle possibili \textit{race condition}\index{race condition} date per
+alle possibili \textit{race condition}\index{\textit{race~condition}} date per
\func{tmpnam} continuano a valere; inoltre in alcune vecchie implementazioni
il valore usato per sostituire le \code{XXXXXX} viene formato con il \acr{pid}
del processo più una lettera, il che mette a disposizione solo 26 possibilità
più gli altri eventuali codici di errore di \func{mkdir}.}
\end{prototype}
\noindent la directory è creata con permessi \code{0700} (al solito si veda
-cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione della
-directory è sempre esclusiva i precedenti problemi di \textit{race
- condition}\index{race condition} non si pongono.
+cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione
+della directory è sempre esclusiva i precedenti problemi di \textit{race
+ condition}\index{\textit{race~condition}} non si pongono.
\section{La manipolazione delle caratteristiche dei files}
Il campo \var{st\_size} contiene la dimensione del file in byte (se si tratta
di un file regolare, nel caso di un link simbolico la dimensione è quella del
-pathname che contiene, per le fifo è sempre nullo).
+\index{\textit{pathname}}\textit{pathname} che contiene, per le fifo è sempre
+nullo).
Il campo \var{st\_blocks} definisce la lunghezza del file in blocchi di 512
byte. Il campo \var{st\_blksize} infine definisce la dimensione preferita per
per \func{truncate} si hanno:
\begin{errlist}
\item[\errcode{EACCES}] il file non ha permesso di scrittura o non si ha il
- permesso di esecuzione una delle directory del pathname.
+ permesso di esecuzione una delle directory del
+ \index{\textit{pathname}}\textit{pathname}.
\item[\errcode{ETXTBSY}] Il file è un programma in esecuzione.
\end{errlist}
ed anche \errval{ENOTDIR}, \errval{ENAMETOOLONG}, \errval{ENOENT},
limiteremo ad un riassunto delle regole generali, entrando nei dettagli più
avanti.
-La prima regola è che per poter accedere ad un file attraverso il suo pathname
-occorre il permesso di esecuzione in ciascuna delle directory che compongono
-il pathname; lo stesso vale per aprire un file nella directory corrente (per
-la quale appunto serve il diritto di esecuzione).
+La prima regola è che per poter accedere ad un file attraverso il suo
+\textit{pathname} occorre il permesso di esecuzione in ciascuna delle
+directory che compongono il \textit{pathname}; lo stesso vale per aprire un
+file nella directory corrente (per la quale appunto serve il diritto di
+esecuzione).
Per una directory infatti il permesso di esecuzione significa che essa può
-essere attraversata nella risoluzione del pathname, ed è distinto dal permesso
-di lettura che invece implica che si può leggere il contenuto della directory.
+essere attraversata nella risoluzione del
+\index{\textit{pathname}}\textit{pathname}, ed è distinto dal permesso di
+lettura che invece implica che si può leggere il contenuto della directory.
Questo significa che se si ha il permesso di esecuzione senza permesso di
lettura si potrà lo stesso aprire un file in una directory (se si hanno i
programma ad una sezione limitata del filesystem, per cui ne parleremo in
questa sezione.
-Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una directory
-di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe sono
- contenute in due campi (rispettivamente \var{pwd} e \var{root}) di
+Come accennato in sez.~\ref{sec:proc_fork} ogni processo oltre ad una
+directory di lavoro, ha anche una directory \textsl{radice}\footnote{entrambe
+ sono contenute in due campi (rispettivamente \var{pwd} e \var{root}) di
\struct{fs\_struct}; vedi fig.~\ref{fig:proc_task_struct}.} che, pur essendo
di norma corrispondente alla radice dell'albero di file e directory come visto
dal kernel (ed illustrato in sez.~\ref{sec:file_organization}), ha per il
processo il significato specifico di directory rispetto alla quale vengono
-risolti i pathname assoluti.\footnote{cioè quando un processo chiede la
- risoluzione di un pathname, il kernel usa sempre questa directory come punto
- di partenza.} Il fatto che questo valore sia specificato per ogni processo
-apre allora la possibilità di modificare le modalità di risoluzione dei
-pathname assoluti da parte di un processo cambiando questa directory, così
-come si fa coi pathname relativi cambiando la directory di lavoro.
+risolti i \index{\textit{pathname}!assoluto}\textit{pathname}
+assoluti.\footnote{cioè quando un processo chiede la risoluzione di un
+ \textit{pathname}, il kernel usa sempre questa directory come punto di
+ partenza.} Il fatto che questo valore sia specificato per ogni processo apre
+allora la possibilità di modificare le modalità di risoluzione dei
+\textit{pathname} assoluti da parte di un processo cambiando questa directory,
+così come si fa coi \index{\textit{pathname}!relativo}\textit{pathname}
+relativi cambiando la directory di lavoro.
Normalmente la directory radice di un processo coincide anche con la radice
del filesystem usata dal kernel, e dato che il suo valore viene ereditato dal
-padre da ogni processo figlio, in generale i processi risolvono i pathname
-assoluti a partire sempre dalla stessa directory, che corrisponde alla
-\file{/} del sistema.
+padre da ogni processo figlio, in generale i processi risolvono i
+\index{\textit{pathname}!assoluto}\textit{pathname} assoluti a partire sempre
+dalla stessa directory, che corrisponde alla \file{/} del sistema.
In certe situazioni però, per motivi di sicurezza, è utile poter impedire che
un processo possa accedere a tutto il filesystem; per far questo si può
\errval{EROFS} e \errval{EIO}.}
\end{prototype}
\noindent in questo modo la directory radice del processo diventerà
-\param{path} (che ovviamente deve esistere) ed ogni pathname assoluto usato
-dalle funzioni chiamate nel processo sarà risolto a partire da essa, rendendo
+\param{path} (che ovviamente deve esistere) ed ogni
+\index{\textit{pathname}!assoluto}\textit{pathname} assoluto usato dalle
+funzioni chiamate nel processo sarà risolto a partire da essa, rendendo
impossibile accedere alla parte di albero sovrastante. Si ha così quella che
viene chiamata una \textit{chroot jail}, in quanto il processo non può più
accedere a file al di fuori della sezione di albero in cui è stato
Questo è il motivo per cui la funzione è efficace solo se dopo averla eseguita
si cedono i privilegi di root. Infatti se per un qualche motivo il processo
resta con la directory di lavoro fuori dalla \textit{chroot jail}, potrà
-comunque accedere a tutto il resto del filesystem usando pathname relativi, i
-quali, partendo dalla directory di lavoro che è fuori della \textit{chroot
- jail}, potranno (con l'uso di \texttt{..}) risalire fino alla radice
-effettiva del filesystem.
+comunque accedere a tutto il resto del filesystem usando
+\index{\textit{pathname}!relativo}\textit{pathname} relativi, i quali,
+partendo dalla directory di lavoro che è fuori della \textit{chroot jail},
+potranno (con l'uso di \texttt{..}) risalire fino alla radice effettiva del
+filesystem.
Ma se ad un processo restano i privilegi di amministratore esso potrà comunque
portare la sua directory di lavoro fuori dalla \textit{chroot jail} in cui si
Questo significa che si può accedere a qualunque periferica del computer,
dalla seriale, alla parallela, alla console, e agli stessi dischi attraverso i
-cosiddetti file di dispositivo\index{file!di dispositivo} (i \textit{device
+cosiddetti file di dispositivo\index{file!di~dispositivo} (i \textit{device
file}). Questi sono dei file speciali agendo sui quali i programmi possono
leggere, scrivere e compiere operazioni direttamente sulle periferiche, usando
le stesse funzioni che si usano per i normali file di dati.
\subsection{L'organizzazione di file e directory}
\label{sec:file_organization}
+\index{\textit{pathname}|(}
In Unix, a differenza di quanto avviene in altri sistemi operativi, tutti i
file vengono tenuti all'interno di un unico albero la cui radice (quella che
viene chiamata \textit{root directory}) viene montata all'avvio. Un file
viene identificato dall'utente usando quello che viene chiamato
-\textit{pathname}\index{pathname}\footnote{il manuale della \acr{glibc}
- depreca questa nomenclatura, che genererebbe confusione poiché \textit{path}
- indica anche un insieme di directory su cui effettuare una ricerca (come
- quello in cui si cercano i comandi). Al suo posto viene proposto l'uso di
- \textit{filename} e di componente per il nome del file all'interno della
- directory. Non seguiremo questa scelta dato che l'uso della parola
- \textit{pathname} è ormai così comune che mantenerne l'uso è senz'altro più
- chiaro dell'alternativa proposta.}, cioè il percorso che si deve fare per
-accedere al file a partire dalla \textit{root directory}, che è composto da
-una serie di nomi separati da una \file{/}.
+\textit{pathname}\footnote{il manuale della \acr{glibc} depreca questa
+ nomenclatura, che genererebbe confusione poiché \textit{path} indica anche
+ un insieme di directory su cui effettuare una ricerca (come quello in cui si
+ cercano i comandi). Al suo posto viene proposto l'uso di \textit{filename} e
+ di componente per il nome del file all'interno della directory. Non
+ seguiremo questa scelta dato che l'uso della parola \textit{pathname} è
+ ormai così comune che mantenerne l'uso è senz'altro più chiaro
+ dell'alternativa proposta.}, cioè il percorso che si deve fare per accedere
+al file a partire dalla \textit{root directory}, che è composto da una serie
+di nomi separati da una \file{/}.
All'avvio del sistema, completata la fase di inizializzazione, il kernel
riceve dal bootloader l'indicazione di quale dispositivo contiene il
contenuto. All'interno dello stesso albero si potranno poi inserire anche
tutti gli altri oggetti visti attraverso l'interfaccia che manipola i file
come le fifo, i link, i socket\index{socket} e gli stessi file di dispositivo
-\index{file!di dispositivo} (questi
+\index{file!di~dispositivo} (questi
ultimi, per convenzione, sono inseriti nella directory \file{/dev}).
Il nome completo di un file viene chiamato \textit{pathname} ed il
sez.~\ref{sec:file_access_control}) devono consentire l'accesso all'intero
\textit{pathname}.
-Se il \textit{pathname}\index{pathname} comincia per \file{/} la ricerca parte
-dalla directory radice del processo; questa, a meno di un \func{chroot} (su
-cui torneremo in sez.~\ref{sec:file_chroot}) è la stessa per tutti i processi
-ed equivale alla directory radice dell'albero dei file: in questo caso si
-parla di un \textsl{pathname assoluto}\index{pathname!assoluto}. Altrimenti la
+Se il \textit{pathname} comincia per \file{/} la ricerca parte dalla directory
+radice del processo; questa, a meno di un \func{chroot} (su cui torneremo in
+sez.~\ref{sec:file_chroot}) è la stessa per tutti i processi ed equivale alla
+directory radice dell'albero dei file: in questo caso si parla di un
+\textsl{pathname assoluto}\index{\textit{pathname}!assoluto}. Altrimenti la
ricerca parte dalla directory corrente (su cui torneremo in
sez.~\ref{sec:file_work_dir}) ed il pathname è detto \textsl{pathname
- relativo}\index{pathname!relativo}.
+ relativo}\index{\textit{pathname}!relativo}.
I nomi \file{.} e \file{..} hanno un significato speciale e vengono inseriti
in ogni directory: il primo fa riferimento alla directory corrente e il
sono implementati come oggetti del \textit{Virtual File System} (vedi
sez.~\ref{sec:file_vfs_work}) e sono presenti in tutti i filesystem unix-like
utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal
-\textit{Virtual File System}\index{Virtual File System} è riportato in
+\textit{Virtual File System}\index{\textit{Virtual~File~System}} è riportato in
tab.~\ref{tab:file_file_types}.
Si tenga ben presente che questa classificazione non ha nulla a che fare con
sez.~\ref{sec:ipc_named_pipe}) ed i \textit{socket}\index{socket} (che
tratteremo in cap.~\ref{cha:socket_intro}) non sono altro che dei riferimenti
per utilizzare delle funzionalità di comunicazione fornite dal kernel. Gli
-altri sono i \textsl{file di dispositivo}\index{file!di dispositivo} (o
+altri sono i \textsl{file di dispositivo}\index{file!di~dispositivo} (o
\textit{device file}) che costituiscono una interfaccia diretta per leggere e
scrivere sui dispositivi fisici; essi vengono suddivisi in due grandi
categorie, \textsl{a blocchi} e \textsl{a caratteri} a seconda delle modalità
ed è completamente trasparente all'utente. Inoltre talvolta si parla di
\textsl{accesso diretto} riferendosi alla capacità, che non ha niente a che
fare con tutto ciò, di effettuare, attraverso degli appositi file di
- dispositivo\index{file!di dispositivo}, operazioni di I/O direttamente sui
+ dispositivo\index{file!di~dispositivo}, operazioni di I/O direttamente sui
dischi senza passare attraverso un filesystem (il cosiddetto \textit{raw
access}, introdotto coi kernel della serie 2.4.x).}
% \textit{inode}, \textit{dentry}, \textit{dcache}.
In Linux il concetto di \textit{everything is a file} è stato implementato
-attraverso il \textit{Virtual File System} (da qui in avanti VFS) che è uno
-strato intermedio che il kernel usa per accedere ai più svariati filesystem
-mantenendo la stessa interfaccia per i programmi in user space. Esso fornisce
-un livello di indirezione che permette di collegare le operazioni di
-manipolazione sui file alle operazioni di I/O, e gestisce l'organizzazione di
-queste ultime nei vari modi in cui i diversi filesystem le effettuano,
-permettendo la coesistenza di filesystem differenti all'interno dello stesso
-albero delle directory.
+attraverso il \textit{Virtual File System}\index{\textit{Virtual~File~System}}
+(da qui in avanti VFS) che è uno strato intermedio che il kernel usa per
+accedere ai più svariati filesystem mantenendo la stessa interfaccia per i
+programmi in user space. Esso fornisce un livello di indirezione che permette
+di collegare le operazioni di manipolazione sui file alle operazioni di I/O, e
+gestisce l'organizzazione di queste ultime nei vari modi in cui i diversi
+filesystem le effettuano, permettendo la coesistenza di filesystem differenti
+all'interno dello stesso albero delle directory.
Quando un processo esegue una system call che opera su un file, il kernel
chiama sempre una funzione implementata nel VFS; la funzione eseguirà le
sui file già aperti.
-\subsection{Il funzionamento del VFS}
+\subsection{Il funzionamento del \textit{Virtual File System}}
\label{sec:file_vfs_work}
-La funzione più importante implementata dal VFS è la system call \func{open}
-che permette di aprire un file. Dato un pathname viene eseguita una ricerca
-dentro la \textit{directory entry cache} (in breve \textit{dcache}), una
-tabella che contiene tutte le \textit{directory entry} (in breve
-\textit{dentry}) che permette di associare in maniera rapida ed efficiente il
-pathname a una specifica \textit{dentry}.
+La funzione più importante implementata dal
+VFS\index{\textit{Virtual~File~System}} è la system call \func{open} che
+permette di aprire un file. Dato un \index{\textit{pathname}}\textit{pathname}
+viene eseguita una ricerca dentro la \textit{directory entry cache} (in breve
+\textit{dcache}), una tabella che contiene tutte le \textit{directory entry}
+(in breve \textit{dentry}) che permette di associare in maniera rapida ed
+efficiente il \textit{pathname} a una specifica \textit{dentry}.
Una singola \textit{dentry} contiene in genere il puntatore ad un
\textit{inode}\index{inode}; quest'ultimo è la struttura base che sta sul
disco e che identifica un singolo oggetto del VFS sia esso un file ordinario,
una directory, un link simbolico, una FIFO, un file di
-dispositivo\index{file!di dispositivo}, o una qualsiasi altra cosa che possa
+dispositivo\index{file!di~dispositivo}, o una qualsiasi altra cosa che possa
essere rappresentata dal VFS (i tipi di file riportati in
tab.~\ref{tab:file_file_types}). A ciascuno di essi è associata pure una
struttura che sta in memoria, e che, oltre alle informazioni sullo specifico
l'albero dei file, ovviamente per non riempire tutta la memoria questa vista è
parziale (la \textit{dcache} cioè contiene solo le \textit{dentry} per i file
per i quali è stato richiesto l'accesso), quando si vuole risolvere un nuovo
-pathname il VFS deve creare una nuova \textit{dentry} e caricare
-l'inode\index{inode} corrispondente in memoria.
+\index{\textit{pathname}}\textit{pathname} il VFS deve creare una nuova
+\textit{dentry} e caricare l'inode\index{inode} corrispondente in memoria.
Questo procedimento viene eseguito dal metodo \code{lookup()}
dell'inode\index{inode} della directory che contiene il file; questo viene
L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la
funzione infatti non controlla il numero di byte letti, per cui nel caso la
stringa letta superi le dimensioni del buffer, si avrà un \textit{buffer
- overflow}\index{buffer overflow}, con sovrascrittura della memoria del
-processo adiacente al buffer.\footnote{questa tecnica è spiegata in dettaglio
- e con molta efficacia nell'ormai famoso articolo di Aleph1 \cite{StS}.}
+ overflow}\index{\textit{buffer~overflow}}, con sovrascrittura della memoria
+del processo adiacente al buffer.\footnote{questa tecnica è spiegata in
+ dettaglio e con molta efficacia nell'ormai famoso articolo di Aleph1
+ \cite{StS}.}
Questa è una delle vulnerabilità più sfruttate per guadagnare accessi
non autorizzati al sistema (i cosiddetti \textit{exploit}), basta
dei puntatori anziché i valori delle variabili, secondo la tecnica spiegata in
sez.~\ref{sec:proc_var_passing}).
-Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL}
-e \var{*n} è zero, la funzione provvede da sola all'allocazione della memoria
+Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL} e
+\var{*n} è zero, la funzione provvede da sola all'allocazione della memoria
necessaria a contenere la linea. In tutti i casi si ottiene dalla funzione un
puntatore all'inizio del testo della linea letta. Un esempio di codice può
-essere il seguente:
-\includecodesnip{listati/getline.c}
-e per evitare memory leak\index{memory leak} occorre ricordarsi di liberare
-\var{ptr} con una \func{free}.
+essere il seguente:
+\includecodesnip{listati/getline.c}
+e per evitare memory leak\index{\textit{memory~leak}} occorre ricordarsi di
+liberare \var{ptr} con una \func{free}.
Il valore di ritorno della funzione indica il numero di caratteri letti
dallo stream (quindi compreso il newline, ma non lo zero di
\bodydesc{Le funzioni ritornano il numero di caratteri stampati.}
\end{functions}
-\noindent le prime due servono per stampare su file (lo standard output
-o quello specificato) la terza permette di stampare su una stringa, in genere
+\noindent le prime due servono per stampare su file (lo standard output o
+quello specificato) la terza permette di stampare su una stringa, in genere
l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se non si ha la
sicurezza assoluta sulle dimensioni del risultato della stampa, eccedere le
dimensioni di \param{str}, con conseguente sovrascrittura di altre variabili e
-possibili \textit{buffer overflow}\index{buffer overflow}; per questo motivo
-si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è:
+possibili \textit{buffer overflow}\index{\textit{buffer~overflow}}; per questo
+motivo si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo
+è:
\begin{prototype}{stdio.h}
{snprintf(char *str, size\_t size, const char *format, ...)}
Identica a \func{sprintf}, ma non scrive su \param{str} più di
Identica a \func{vsprintf}, ma non scrive su \param{str} più di
\param{size} caratteri.
\end{prototype}
-\noindent in modo da evitare possibili buffer overflow\index{buffer overflow}.
+\noindent in modo da evitare possibili buffer
+overflow\index{\textit{buffer~overflow}}.
Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
argument}) l'indirizzo della stringa allocata automaticamente dalle
funzioni. Occorre inoltre ricordarsi di invocare \func{free} per liberare
detto puntatore quando la stringa non serve più, onde evitare memory
-leak\index{memory leak}.
+leak\index{\textit{memory~leak}}.
Infine una ulteriore estensione GNU definisce le due funzioni \func{dprintf} e
\func{vdprintf}, che prendono un file descriptor al posto dello stream. Altre
dal file sottostante lo stream, quando cioè si ha a che fare con quello che
viene detto un file ad \textsl{accesso casuale}.\footnote{dato che in un
sistema Unix esistono vari tipi di file, come le fifo ed i file di
- dispositivo\index{file!di dispositivo}, non è scontato che questo sia sempre
+ dispositivo\index{file!di~dispositivo}, non è scontato che questo sia sempre
vero.}
In GNU/Linux ed in generale in ogni sistema unix-like la posizione nel file è
\label{sec:file_open}
La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è
-quella che crea l'associazione fra un pathname ed un file descriptor, il suo
+quella che crea l'associazione fra un
+\index{\textit{pathname}}\textit{pathname} ed un file descriptor, il suo
prototipo è:
\begin{functions}
\headdecl{sys/types.h}
dispositivo che non esiste.
\item[\errcode{ETXTBSY}] si è cercato di accedere in scrittura all'immagine
di un programma in esecuzione.
- \item[\errcode{ELOOP}] si sono incontrati troppi link simbolici nel risolvere
- pathname o si è indicato \const{O\_NOFOLLOW} e \param{pathname} è un link
- simbolico.
+ \item[\errcode{ELOOP}] si sono incontrati troppi link simbolici nel
+ risolvere il \textit{pathname} o si è indicato \const{O\_NOFOLLOW} e
+ \param{pathname} è un link simbolico.
\end{errlist}
ed inoltre \errval{EACCES}, \errval{ENAMETOOLONG}, \errval{ENOENT},
\errval{EROFS}, \errval{EFAULT}, \errval{ENOSPC}, \errval{ENOMEM},
\hline % modalità di apertura del file
\hline
\const{O\_CREAT} & se il file non esiste verrà creato, con le regole di
- titolarità del file viste in sez.~\ref{sec:file_ownership}. L'argomento
- \param{mode} deve essere specificato. \\
- \const{O\_EXCL} & usato in congiunzione con \const{O\_CREAT} fa sì che
- l'esistenza del file diventi un errore\protect\footnotemark\ che fa fallire
- \func{open} con \errcode{EEXIST}. \\
- \const{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo
- valore specifica anche una modalità di operazione (vedi sotto), e
- comporta che \func{open} ritorni immediatamente (l'opzione ha senso
- solo per le fifo, torneremo questo in sez.~\ref{sec:ipc_named_pipe}). \\
- \const{O\_NOCTTY} & se \param{pathname} si riferisce ad un dispositivo di
- terminale, questo non diventerà il terminale di controllo, anche se il
- processo non ne ha ancora uno (si veda sez.~\ref{sec:sess_ctrl_term}). \\
+ titolarità del file viste in
+ sez.~\ref{sec:file_ownership}. L'argomento
+ \param{mode} deve essere specificato. \\
+ \const{O\_EXCL} & usato in congiunzione con \const{O\_CREAT} fa sì che
+ l'esistenza del file diventi un
+ errore\protect\footnotemark\ che fa fallire
+ \func{open} con \errcode{EEXIST}. \\
+ \const{O\_NONBLOCK}& apre il file in modalità non bloccante. Questo
+ valore specifica anche una modalità di operazione (vedi
+ sotto), e comporta che \func{open} ritorni
+ immediatamente (l'opzione ha senso solo per le fifo,
+ torneremo questo in sez.~\ref{sec:ipc_named_pipe}). \\
+ \const{O\_NOCTTY}& se \param{pathname} si riferisce ad un dispositivo di
+ terminale, questo non diventerà il terminale di
+ controllo, anche se il processo non ne ha ancora uno
+ (si veda sez.~\ref{sec:sess_ctrl_term}). \\
\const{O\_SHLOCK} & opzione di BSD, acquisisce uno shared lock (vedi
- sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
+ sez.~\ref{sec:file_locking}) sul file. Non è
+ disponibile in Linux. \\
\const{O\_EXLOCK} & opzione di BSD, acquisisce uno lock esclusivo (vedi
- sez.~\ref{sec:file_locking}) sul file. Non è disponibile in Linux. \\
- \const{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di
- apertura consente la scrittura, allora la sua lunghezza verrà troncata a
- zero. Se il file è un terminale o una fifo il flag verrà ignorato, negli
- altri casi il comportamento non è specificato. \\
- \const{O\_NOFOLLOW} & se \param{pathname} è un link simbolico la chiamata
- fallisce. Questa è un'estensione BSD aggiunta in Linux dal kernel 2.1.126.
- Nelle versioni precedenti i link simbolici sono sempre seguiti, e questa
- opzione è ignorata. \\
- \const{O\_DIRECTORY} & se \param{pathname} non è una directory la chiamata
- fallisce. Questo flag è specifico di Linux ed è stato introdotto con il
- kernel 2.1.126 per evitare dei
- \textit{DoS}\index{DoS}\protect\footnotemark\ quando
- \func{opendir} viene chiamata su una
- fifo o su un device di unità a nastri, non deve essere utilizzato al di
- fuori dell'implementazione di \func{opendir}. \\
- \const{O\_LARGEFILE} & nel caso di sistemi a 32 bit che supportano file di
- grandi dimensioni consente di aprire file le cui dimensioni non possono
- essere rappresentate da numeri a 31 bit. \\
+ sez.~\ref{sec:file_locking}) sul file. Non è
+ disponibile in Linux. \\
+ \const{O\_TRUNC} & se il file esiste ed è un file di dati e la modalità di
+ apertura consente la scrittura, allora la sua
+ lunghezza verrà troncata a zero. Se il file è un
+ terminale o una fifo il flag verrà ignorato, negli
+ altri casi il comportamento non è specificato. \\
+ \const{O\_NOFOLLOW}&se \param{pathname} è un link simbolico la chiamata
+ fallisce. Questa è un'estensione BSD aggiunta in Linux
+ dal kernel 2.1.126. Nelle versioni precedenti i link
+ simbolici sono sempre seguiti, e questa opzione è
+ ignorata. \\
+ \const{O\_DIRECTORY}& se \param{pathname} non è una directory la chiamata
+ fallisce. Questo flag è specifico di Linux ed è stato
+ introdotto con il kernel 2.1.126 per evitare dei
+ \textit{DoS}\index{DoS}\protect\footnotemark\ quando
+ \func{opendir} viene chiamata su una fifo o su un
+ device di unità a nastri, non deve essere utilizzato
+ al di fuori dell'implementazione di \func{opendir}. \\
+ \const{O\_LARGEFILE}& nel caso di sistemi a 32 bit che supportano file di
+ grandi dimensioni consente di aprire file le cui
+ dimensioni non possono essere rappresentate da numeri
+ a 31 bit. \\
\hline
\hline % modalità di operazione col file
\const{O\_APPEND} & il file viene aperto in append mode. Prima di ciascuna
- scrittura la posizione corrente viene sempre impostata alla fine del
- file. Può causare corruzione del file con NFS se più di un processo scrive
- allo stesso tempo.\footnotemark\\
- \const{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per
- le operazioni di I/O (che tratteremo in sez.~\ref{sec:file_noblocking}):
- questo significa il fallimento di \func{read} in assenza di dati da
- leggere e quello di \func{write} in caso di impossibilità di scrivere
- immediatamente. Questa modalità ha senso solo per le fifo e per alcuni
- file di dispositivo. \\
+ scrittura la posizione corrente viene sempre impostata
+ alla fine del file. Può causare corruzione del file
+ con NFS se più di un processo scrive allo stesso
+ tempo.\footnotemark\\
+ \const{O\_NONBLOCK}&il file viene aperto in modalità non bloccante per
+ le operazioni di I/O (che tratteremo in
+ sez.~\ref{sec:file_noblocking}): questo significa il
+ fallimento di \func{read} in assenza di dati da
+ leggere e quello di \func{write} in caso di
+ impossibilità di scrivere immediatamente. Questa
+ modalità ha senso solo per le fifo e per alcuni file
+ di dispositivo. \\
\const{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di
- \const{O\_NONBLOCK}.\\
- \const{O\_ASYNC} & apre il file per l'I/O in modalità
- asincrona (vedi sez.~\ref{sec:file_asyncronous_io}). Quando è impostato
- viene generato il segnale \const{SIGIO} tutte le volte che sono disponibili
- dati in input sul file. \\
- \const{O\_SYNC} & apre il file per l'input/output sincrono: ogni
- \func{write} bloccherà fino al completamento della scrittura di tutti i
- dati sull'hardware sottostante.\\
- \const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\
- \const{O\_NOATIME} & blocca l'aggiornamento dei tempi di accesso dei
- file (vedi sez.~\ref{sec:file_file_times}). Per molti filesystem questa
- funzionalità non è disponibile per il singolo file ma come opzione in fase
- di montaggio.\\
+ \const{O\_NONBLOCK}.\\
+ \const{O\_ASYNC} & apre il file per l'I/O in modalità asincrona (vedi
+ sez.~\ref{sec:file_asyncronous_io}). Quando è
+ impostato viene generato il segnale \const{SIGIO}
+ tutte le volte che sono disponibili dati in input
+ sul file. \\
+ \const{O\_SYNC} & apre il file per l'input/output sincrono: ogni
+ \func{write} bloccherà fino al completamento della
+ scrittura di tutti i dati sull'hardware sottostante.\\
+ \const{O\_FSYNC} & sinonimo di \const{O\_SYNC}. \\
+ \const{O\_NOATIME}& blocca l'aggiornamento dei tempi di accesso dei
+ file (vedi sez.~\ref{sec:file_file_times}). Per molti
+ filesystem questa funzionalità non è disponibile per
+ il singolo file ma come opzione in fase di montaggio.\\
\hline
\end{tabular}
\caption{Valori e significato dei vari bit del \textit{file status flag}.}
\footnotetext[2]{la pagina di manuale di \func{open} segnala che questa
opzione è difettosa su NFS, e che i programmi che la usano per stabilire un
\textsl{file di lock}\index{file!di lock} possono incorrere in una race
- condition\index{race condition}. Si consiglia come alternativa di usare un
- file con un nome univoco e la funzione \func{link} per verificarne
+ condition\index{\textit{race~condition}}. Si consiglia come alternativa di
+ usare un file con un nome univoco e la funzione \func{link} per verificarne
l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).}
\footnotetext[3]{\textit{Denial of Service}\index{DoS}, si chiamano così
aperto anche da un altro processo che vi ha scritto, la fine del file può
essersi spostata, ma noi scriveremo alla posizione impostata in precedenza
(questa è una potenziale sorgente di \textit{race condition}
-\index{race condition}, vedi sez.~\ref{sec:file_atomic}).
+\index{\textit{race~condition}}, vedi sez.~\ref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per
vari processi devono scrivere alla fine di un file (ad esempio un file di
log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla
fine del file e poi scrivere può condurre ad una \textit{race
- condition}\index{race condition}: infatti può succedere che un secondo
-processo scriva alla fine del file fra la \func{lseek} e la \func{write}; in
-questo caso, come abbiamo appena visto, il file sarà esteso, ma il nostro
-primo processo avrà ancora la posizione corrente impostata con la \func{lseek}
-che non corrisponde più alla fine del file, e la successiva \func{write}
-sovrascriverà i dati del secondo processo.
+ condition}\index{\textit{race~condition}}: infatti può succedere che un
+secondo processo scriva alla fine del file fra la \func{lseek} e la
+\func{write}; in questo caso, come abbiamo appena visto, il file sarà esteso,
+ma il nostro primo processo avrà ancora la posizione corrente impostata con la
+\func{lseek} che non corrisponde più alla fine del file, e la successiva
+\func{write} sovrascriverà i dati del secondo processo.
Il problema è che usare due system call in successione non è un'operazione
atomica; il problema è stato risolto introducendo la modalità
creare un \textsl{file di lock}\index{file!di lock}, bloccandosi se il file
esiste. In questo caso la sequenza logica porterebbe a verificare prima
l'esistenza del file con una \func{stat} per poi crearlo con una \func{creat};
-di nuovo avremmo la possibilità di una race condition\index{race condition} da
-parte di un altro processo che crea lo stesso file fra il controllo e la
-creazione.
+di nuovo avremmo la possibilità di una race
+condition\index{\textit{race~condition}} da parte di un altro processo che
+crea lo stesso file fra il controllo e la creazione.
Per questo motivo sono stati introdotti per \func{open} i due flag
\const{O\_CREAT} e \const{O\_EXCL}. In questo modo l'operazione di controllo
della \textit{file table} a cui entrambi fanno riferimento). L'unica
differenza fra due file descriptor duplicati è che ciascuno avrà il suo
\textit{file descriptor flag}; a questo proposito va specificato che nel caso
-di \func{dup} il flag di \textit{close-on-exec}\index{close-on-exec} (vedi
-sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato
-nella copia.
+di \func{dup} il flag di \textit{close-on-exec}\index{\textit{close-on-exec}}
+(vedi sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre
+cancellato nella copia.
L'uso principale di questa funzione è per la redirezione dell'input e
dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
massimo numero di descrittori consentito.
\item[\const{F\_SETFD}] imposta il valore del \textit{file descriptor flag} al
valore specificato con \param{arg}. Al momento l'unico bit usato è quello di
- \textit{close-on-exec}\index{close-on-exec}, identificato dalla costante
- \const{FD\_CLOEXEC}, che serve a richiedere che il file venga chiuso nella
- esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}). Ritorna un
- valore nullo in caso di successo e -1 in caso di errore.
+ \textit{close-on-exec}\index{\textit{close-on-exec}}, identificato dalla
+ costante \const{FD\_CLOEXEC}, che serve a richiedere che il file venga
+ chiuso nella esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}).
+ Ritorna un valore nullo in caso di successo e -1 in caso di errore.
\item[\const{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di
\param{fd} o -1 in caso di errore; se \const{FD\_CLOEXEC} è impostato i file
descriptor aperti vengono chiusi attraverso una \func{exec} altrimenti (il
\textit{file locking}\index{file!locking} saranno esaminate in
sez.~\ref{sec:file_locking}).
-
Si tenga presente infine che quando si usa la funzione per determinare le
modalità di accesso con cui è stato aperto il file (attraverso l'uso del
comando \const{F\_GETFL}) è necessario estrarre i bit corrispondenti nel
(e non possono accedere direttamente alle zone di memoria riservate o alle
porte di input/output).
-Una parte del kernel, lo \textit{scheduler}\index{scheduler}, si occupa di
-stabilire, ad intervalli fissi e sulla base di un opportuno calcolo delle
-priorità, quale ``\textsl{processo}'' deve essere posto in esecuzione (il
-cosiddetto \textit{preemptive scheduling}\index{preemptive scheduling}).
-Questo verrà comunque eseguito in modalità protetta; quando necessario il
-processo potrà accedere alle risorse hardware soltanto attraverso delle
-opportune chiamate al sistema che restituiranno il controllo al kernel.
+Una parte del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, si
+occupa di stabilire, ad intervalli fissi e sulla base di un opportuno calcolo
+delle priorità, quale ``\textsl{processo}'' deve essere posto in esecuzione
+(il cosiddetto \textit{preemptive
+ scheduling}\index{\textit{preemptive~scheduling}}). Questo verrà comunque
+eseguito in modalità protetta; quando necessario il processo potrà accedere
+alle risorse hardware soltanto attraverso delle opportune chiamate al sistema
+che restituiranno il controllo al kernel.
La memoria viene sempre gestita dal kernel attraverso il meccanismo della
-\textsl{memoria virtuale}\index{memoria virtuale}, che consente di assegnare a
+\textsl{memoria virtuale}\index{memoria~virtuale}, che consente di assegnare a
ciascun processo uno spazio di indirizzi ``\textsl{virtuale}'' (vedi
sez.~\ref{sec:proc_memory}) che il kernel stesso, con l'ausilio della unità di
gestione della memoria, si incaricherà di rimappare automaticamente sulla
Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
intermedio su un file temporaneo. Questo però non tiene conto del fatto che un
\textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una
-evidente race condition\index{race condition} in caso di accesso simultaneo a
-detto file.\footnote{il problema potrebbe essere superato determinando in
- anticipo un nome appropriato per il file temporaneo, che verrebbe utilizzato
- dai vari sotto-processi, e cancellato alla fine della loro esecuzione; ma a
- questo le cose non sarebbero più tanto semplici.} L'uso di una pipe invece
-permette di risolvere il problema in maniera semplice ed elegante, oltre ad
-essere molto più efficiente, dato che non si deve scrivere su disco.
+evidente \textit{race condition}\index{\textit{race~condition}} in caso di
+accesso simultaneo a detto file.\footnote{il problema potrebbe essere superato
+ determinando in anticipo un nome appropriato per il file temporaneo, che
+ verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
+ loro esecuzione; ma a questo le cose non sarebbero più tanto semplici.}
+L'uso di una pipe invece permette di risolvere il problema in maniera semplice
+ed elegante, oltre ad essere molto più efficiente, dato che non si deve
+scrivere su disco.
Il programma ci servirà anche come esempio dell'uso delle funzioni di
duplicazione dei file descriptor che abbiamo trattato in
lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
qual caso però occorre stare molto attenti alla possibili situazioni di
stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si
- avrà un deadlock\index{deadlock} immediato, dato che il processo si blocca e
- non potrà quindi mai eseguire le funzioni di scrittura.}
+ avrà un deadlock\index{\textit{deadlock}} immediato, dato che il processo si
+ blocca e non potrà quindi mai eseguire le funzioni di scrittura.}
Per la loro caratteristica di essere accessibili attraverso il filesystem, è
piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle
occorrerà definire la speciale variabile di ambiente \code{LD\_LIBRARY\_PATH}
in modo che il linker dinamico possa accedervi.
-In generale questa variabile indica il pathname della directory contenente la
+In generale questa variabile indica il
+\index{\textit{pathname}}\textit{pathname} della directory contenente la
libreria. Nell'ipotesi (che daremo sempre per verificata) che si facciano le
prove direttamente nella directory dei sorgenti (dove di norma vengono creati
sia i programmi che la libreria), il comando da dare sarà \code{export
\end{functions}
La funzione determina un valore della chiave sulla base di \param{pathname},
-che deve specificare il pathname di un file effettivamente esistente e di un
-numero di progetto \param{proj\_id)}, che di norma viene specificato come
-carattere, dato che ne vengono utilizzati solo gli 8 bit meno
-significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS,
- l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, le \acr{glibc}
- usano il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli
- 8 bit meno significativi.}
+che deve specificare il \index{\textit{pathname}}\textit{pathname} di un file
+effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di
+norma viene specificato come carattere, dato che ne vengono utilizzati solo
+gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in
+ SunOS, l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, le
+ \acr{glibc} usano il prototipo specificato da XPG4, ma vengono lo stesso
+ utilizzati gli 8 bit meno significativi.}
Il problema è che anche così non c'è la sicurezza che il valore della chiave
sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)}
funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
una di queste strutture alla volta; ad esempio non si può scrivere un server
che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
-di \textit{polling}\index{polling} che esegua un ciclo di attesa su ciascuna
-di esse.
+di \textit{polling}\index{\textit{polling}} che esegua un ciclo di attesa su
+ciascuna di esse.
Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
I semafori non sono meccanismi di intercomunicazione diretta come quelli
(pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare
dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o
-di protezione per le \textsl{sezioni critiche}\index{sezioni critiche} del
+di protezione per le \textsl{sezioni critiche}\index{sezioni~critiche} del
codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}).
Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last}
di \struct{semid\_ds}.}. Nella struttura viene memorizzato il riferimento
alle operazioni richieste (nel campo \var{sops}, che è un puntatore ad una
-struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper}) poi
-quest'ultimo viene messo stato di attesa e viene invocato lo
-scheduler\index{scheduler} per passare all'esecuzione di un altro processo.
+struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper})
+poi quest'ultimo viene messo stato di attesa e viene invocato lo
+scheduler\index{\textit{scheduler}} per passare all'esecuzione di un altro
+processo.
Se invece tutte le operazioni possono avere successo queste vengono eseguite
immediatamente, dopo di che il kernel esegue una scansione della coda di
\var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o
il creatore del segmento, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
-\item[\const{SHM\_LOCK}] Abilita il
- \textit{memory locking}\index{memory locking}\footnote{impedisce cioè che la
+\item[\const{SHM\_LOCK}] Abilita il \textit{memory
+ locking}\index{\textit{memory~locking}}\footnote{impedisce cioè che la
memoria usata per il segmento venga salvata su disco dal meccanismo della
- memoria virtuale\index{memoria virtuale}; si ricordi quanto trattato in
+ memoria virtuale\index{memoria~virtuale}; si ricordi quanto trattato in
sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
l'amministratore può utilizzare questo comando.
-\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
- di memoria condivisa. Solo l'amministratore può utilizzare questo comando.
+\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory
+ locking}\index{\textit{memory~locking}} sul segmento di memoria condivisa.
+ Solo l'amministratore può utilizzare questo comando.
\end{basedescript}
i primi tre comandi sono gli stessi già visti anche per le code di messaggi e
gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche
previste da Linux, che permettono di abilitare e disabilitare il meccanismo
-della memoria virtuale\index{memoria virtuale} per il segmento.
+della memoria virtuale\index{memoria~virtuale} per il segmento.
L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura
sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
standard POSIX.1, ciò non toglie che in alcune implementazioni questa
tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
- è comunque soggetti alla possibilità di una race
- condition\index{race condition}.} che essa ritorni un errore quando usata
-con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la creazione di
-un \textsl{file di lock} può essere eseguita atomicamente, il processo che
-crea il file con successo si può considerare come titolare del lock (e della
-risorsa ad esso associata) mentre il rilascio si può eseguire con una chiamata
-ad \func{unlink}.
+ è comunque soggetti alla possibilità di una race
+ condition\index{\textit{race~condition}}.} che essa ritorni un errore quando
+usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la
+creazione di un \textsl{file di lock} può essere eseguita atomicamente, il
+processo che crea il file con successo si può considerare come titolare del
+lock (e della risorsa ad esso associata) mentre il rilascio si può eseguire
+con una chiamata ad \func{unlink}.
Un esempio dell'uso di questa funzione è mostrato dalle funzioni
\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
-può essere eseguito solo con una tecnica di \textit{polling}\index{polling},
-ed è quindi molto inefficiente.
+può essere eseguito solo con una tecnica di
+\textit{polling}\index{\textit{polling}}, ed è quindi molto inefficiente.
La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
illustrati in precedenza, la tecnica alternativa di sincronizzazione più
comune è quella di fare ricorso al \textit{file locking}\index{file!locking}
-(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file creato
-per l'occasione per ottenere un write lock. In questo modo potremo usare il
-lock come un \textit{mutex}: per bloccare la risorsa basterà acquisire il
-lock, per sbloccarla basterà rilasciare il lock. Una richiesta fatta con un
-write lock metterà automaticamente il processo in stato di attesa, senza
-necessità di ricorrere al \textit{polling}\index{polling} per determinare la
-disponibilità della risorsa, e al rilascio della stessa da parte del processo
-che la occupava si otterrà il nuovo lock atomicamente.
+(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file
+creato per l'occasione per ottenere un write lock. In questo modo potremo
+usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
+acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
+fatta con un write lock metterà automaticamente il processo in stato di
+attesa, senza necessità di ricorrere al
+\textit{polling}\index{\textit{polling}} per determinare la disponibilità
+della risorsa, e al rilascio della stessa da parte del processo che la
+occupava si otterrà il nuovo lock atomicamente.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
-\textit{Posix IPC names}\index{Posix IPC names}, che sono sostanzialmente
-equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC
-Posix prendono come primo argomento una stringa che indica uno di questi nomi;
-lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
-possono avere o meno una corrispondenza sul filesystem; tutto quello che è
-richiesto è che:
+\textit{Posix IPC names}\index{\textit{Posix~IPC~names}}, che sono
+sostanzialmente equivalenti ai nomi dei file. Tutte le funzioni che creano un
+oggetto di IPC Posix prendono come primo argomento una stringa che indica uno
+di questi nomi; lo standard è molto generico riguardo l'implementazione, ed i
+nomi stessi possono avere o meno una corrispondenza sul filesystem; tutto
+quello che è richiesto è che:
\begin{itemize}
\item i nomi devono essere conformi alle regole che caratterizzano i
- \textit{pathname}, in particolare non essere più lunghi di \const{PATH\_MAX}
- byte e terminati da un carattere nullo.
+ \index{\textit{pathname}}\textit{pathname}, in particolare non essere più
+ lunghi di \const{PATH\_MAX} byte e terminati da un carattere nullo.
\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso
nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del
nome dipende dall'implementazione.
(rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si
faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e
sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
-sono considerati come un pathname assoluto (comprendente eventuali
-sottodirectory) rispetto a queste radici.
+sono considerati come un \index{\textit{pathname}!assoluto}\textit{pathname}
+assoluto (comprendente eventuali sottodirectory) rispetto a queste radici.
Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
nell'albero dei file, e possono essere maneggiati con le usuali funzioni e
utilizzabile anche per la memoria condivisa; esso infatti non ha dimensione
fissa, ed usa direttamente la cache interna del kernel (che viene usata
anche per la shared memory in stile SysV). In più i suoi contenuti, essendo
- trattati direttamente dalla memoria virtuale\index{memoria virtuale} possono
+ trattati direttamente dalla memoria virtuale\index{memoria~virtuale} possono
essere salvati sullo swap automaticamente.} che viene attivato abilitando
l'opzione \texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.
Come accennato nell'introduzione il \textsl{processo} è l'unità di base con
cui un sistema unix-like alloca ed utilizza le risorse. Questo capitolo
tratterà l'interfaccia base fra il sistema e i processi, come vengono passati
-i parametri, come viene gestita e allocata la memoria, come un processo può
+gli argomenti, come viene gestita e allocata la memoria, come un processo può
richiedere servizi al sistema e cosa deve fare quando ha finito la sua
esecuzione. Nella sezione finale accenneremo ad alcune problematiche generiche
di programmazione.
fallimento, \var{errno} non viene modificata.}
\end{prototype}
-In questo caso la funzione da chiamare all'uscita prende i due parametri
+In questo caso la funzione da chiamare all'uscita prende i due argomenti
specificati nel prototipo, dovrà cioè essere definita come \code{void
function(int status, void *argp)}. Il primo argomento sarà inizializzato
allo stato di uscita con cui è stata chiamata \func{exit} ed il secondo al
Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli
di basso livello dipendono spesso in maniera diretta dall'architettura
dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è
-la cosiddetta \textsl{memoria virtuale}\index{memoria virtuale} che consiste
+la cosiddetta \textsl{memoria virtuale}\index{memoria~virtuale} che consiste
nell'assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare,
in cui gli indirizzi vanno da zero ad un qualche valore massimo.\footnote{nel
caso di Linux fino al kernel 2.2 detto massimo era, per macchine a 32bit, di
sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria
virtuale di tutti i processi che hanno detta funzione nel loro codice.
-La corrispondenza fra le pagine della memoria virtuale e quelle della memoria
-fisica della macchina viene gestita in maniera trasparente dall'hardware di
-gestione della memoria (la \textit{Memory Management Unit} del processore).
-Poiché in genere la memoria fisica è solo una piccola frazione della memoria
-virtuale, è necessario un meccanismo che permetta di trasferire le pagine che
-servono dal supporto su cui si trovano in memoria, eliminando quelle che non
-servono. Questo meccanismo è detto \textsl{paginazione}\index{paginazione} (o
-\textit{paging}), ed è uno dei compiti principali del kernel.
+La corrispondenza fra le pagine della \index{memoria~virtuale}memoria virtuale
+e quelle della memoria fisica della macchina viene gestita in maniera
+trasparente dall'hardware di gestione della memoria (la \textit{Memory
+ Management Unit} del processore). Poiché in genere la memoria fisica è solo
+una piccola frazione della memoria virtuale, è necessario un meccanismo che
+permetta di trasferire le pagine che servono dal supporto su cui si trovano in
+memoria, eliminando quelle che non servono. Questo meccanismo è detto
+\textsl{paginazione}\index{paginazione} (o \textit{paging}), ed è uno dei
+compiti principali del kernel.
Quando un processo cerca di accedere ad una pagina che non è nella memoria
-reale, avviene quello che viene chiamato un
-\textit{page fault}\index{page fault};
-l'hardware di gestione della memoria genera un'interruzione e passa
-il controllo al kernel il quale sospende il processo e si incarica di mettere
-in RAM la pagina richiesta (effettuando tutte le operazioni necessarie per
-reperire lo spazio necessario), per poi restituire il controllo al processo.
+reale, avviene quello che viene chiamato un \textit{page
+ fault}\index{\textit{page~fault}}; l'hardware di gestione della memoria
+genera un'interruzione e passa il controllo al kernel il quale sospende il
+processo e si incarica di mettere in RAM la pagina richiesta (effettuando
+tutte le operazioni necessarie per reperire lo spazio necessario), per poi
+restituire il controllo al processo.
Dal punto di vista di un processo questo meccanismo è completamente
trasparente, e tutto avviene come se tutte le pagine fossero sempre
commette quando si è manipolato male un puntatore e genera quello che viene
chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
scrivere da un indirizzo per il quale non esiste un'associazione della pagina
-virtuale, il kernel risponde al relativo \textit{page fault}\index{page fault}
-mandando un segnale \const{SIGSEGV} al processo, che normalmente ne causa la
-terminazione immediata.
+virtuale, il kernel risponde al relativo \textit{page
+ fault}\index{\textit{page~fault}} mandando un segnale \const{SIGSEGV} al
+processo, che normalmente ne causa la terminazione immediata.
È pertanto importante capire come viene strutturata \textsl{la memoria
- virtuale}\index{page fault} di un processo. Essa viene divisa in
+ virtuale}\index{\textit{page~fault}} di un processo. Essa viene divisa in
\textsl{segmenti}, cioè un insieme contiguo di indirizzi virtuali ai quali il
processo può accedere. Solitamente un programma C viene suddiviso nei
seguenti segmenti:
Il problema più comune e più difficile da risolvere che si incontra con le
routine di allocazione è quando non viene opportunamente liberata la memoria
non più utilizzata, quello che in inglese viene chiamato \textit{memory
- leak}\index{memory leak}, cioè una \textsl{perdita di memoria}.
+ leak}\index{\textit{memory~leak}}, cioè una \textsl{perdita di memoria}.
Un caso tipico che illustra il problema è quello in cui in una subroutine si
alloca della memoria per uso locale senza liberarla prima di uscire. La
momento, in corrispondenza ad una qualunque chiamata di \func{malloc}, che può
essere in una sezione del codice che non ha alcuna relazione con la subroutine
che contiene l'errore. Per questo motivo è sempre molto difficile trovare un
-\textit{memory leak}\index{memory leak}.
+\textit{memory leak}\index{\textit{memory~leak}}.
In C e C++ il problema è particolarmente sentito. In C++, per mezzo della
programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente
\label{sec:proc_mem_alloca}
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
-problemi di \textit{memory leak}\index{memory leak} descritti in precedenza, è
-la funzione \funcd{alloca}, che invece di allocare la memoria nello heap usa
-il segmento di stack della funzione corrente. La sintassi è identica a quella
-di \func{malloc}, il suo prototipo è:
+problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in
+precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
+nello heap usa il segmento di stack della funzione corrente. La sintassi è
+identica a quella di \func{malloc}, il suo prototipo è:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
Alloca \param{size} byte nello stack.
rilasciata automaticamente al ritorno della funzione.
Come è evidente questa funzione ha molti vantaggi, anzitutto permette di
-evitare alla radice i problemi di memory leak\index{memory leak}, dato che non
-serve più la deallocazione esplicita; inoltre la deallocazione automatica
-funziona anche quando si usa \func{longjmp} per uscire da una subroutine con
-un salto non locale da una funzione (vedi sez.~\ref{sec:proc_longjmp}).
+evitare alla radice i problemi di memory leak\index{\textit{memory~leak}},
+dato che non serve più la deallocazione esplicita; inoltre la deallocazione
+automatica funziona anche quando si usa \func{longjmp} per uscire da una
+subroutine con un salto non locale da una funzione (vedi
+sez.~\ref{sec:proc_longjmp}).
Un altro vantaggio è che in Linux la funzione è molto più veloce di
\func{malloc} e non viene sprecato spazio, infatti non è necessario gestire un
% \label{sec:proc_mem_malloc_custom}
-\subsection{Il controllo della memoria virtuale\index{memoria virtuale}}
+\subsection{Il controllo della memoria virtuale}
\label{sec:proc_mem_lock}
+\index{memoria~virtuale|(}
Come spiegato in sez.~\ref{sec:proc_mem_gen} il kernel gestisce la memoria
virtuale in maniera trasparente ai processi, decidendo quando rimuovere pagine
dalla memoria per metterle nello swap, sulla base dell'utilizzo corrente da
crittografia richiedono il blocco di alcune pagine di memoria.
\end{itemize}
+\index{\textit{memory~locking}|(}
Il meccanismo che previene la paginazione\index{paginazione} di parte della
memoria virtuale di un processo è chiamato \textit{memory locking} (o
\textsl{blocco della memoria}). Il blocco è sempre associato alle pagine della
comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di
tutti i suoi \textit{memory lock}. Infine \textit{memory lock} non sono
ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on
- write}\index{copy on write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi
- virtuali del figlio sono mantenuti sullo stesso segmento di RAM del padre,
- quindi fintanto che un figlio non scrive su un segmento, può usufruire del
- memory lock del padre.}
+ write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio
+ sono mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che
+ un figlio non scrive su un segmento, può usufruire del \textit{memory lock}
+ del padre.}
Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce
la memoria fisica disponibile nel sistema, questo ha un evidente impatto su
In ogni caso un processo real-time che deve entrare in una sezione critica
deve provvedere a riservare memoria sufficiente prima dell'ingresso, per
-scongiurare l'occorrenza di un eventuale \textit{page fault}\index{page fault}
-causato dal meccanismo di \textit{copy on write}\index{copy on write}.
-Infatti se nella sezione critica si va ad utilizzare memoria che non è ancora
-stata riportata in RAM si potrebbe avere un page fault durante l'esecuzione
-della stessa, con conseguente rallentamento (probabilmente inaccettabile) dei
-tempi di esecuzione.
+scongiurare l'occorrenza di un eventuale \textit{page
+ fault}\index{\textit{page~fault}} causato dal meccanismo di \textit{copy on
+ write}\index{\textit{copy~on~write}}. Infatti se nella sezione critica si
+va ad utilizzare memoria che non è ancora stata riportata in RAM si potrebbe
+avere un page fault durante l'esecuzione della stessa, con conseguente
+rallentamento (probabilmente inaccettabile) dei tempi di esecuzione.
In genere si ovvia a questa problematica chiamando una funzione che ha
allocato una quantità sufficientemente ampia di variabili automatiche, in modo
che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri
che esse siano state effettivamente portate in memoria, ci si scrive sopra.
+\index{memoria~virtuale|)}
+\index{\textit{memory~locking}|)}
-\section{Parametri, opzioni ed ambiente di un processo}
+\section{Argomenti, opzioni ed ambiente di un processo}
\label{sec:proc_options}
-Tutti i programmi hanno la possibilità di ricevere parametri e opzioni quando
-vengono lanciati. Il passaggio dei parametri è effettuato attraverso gli
+Tutti i programmi hanno la possibilità di ricevere argomenti e opzioni quando
+vengono lanciati. Il passaggio degli argomenti è effettuato attraverso gli
argomenti \param{argc} e \param{argv} della funzione \func{main}, che vengono
passati al programma dalla shell (o dal processo che esegue la \func{exec},
secondo le modalità che vedremo in sez.~\ref{sec:proc_exec}) quando questo
viene messo in esecuzione.
-Oltre al passaggio dei parametri, un'altra modalità che permette di passare
+Oltre al passaggio degli argomenti, un'altra modalità che permette di passare
delle informazioni che modifichino il comportamento di un programma è quello
dell'uso del cosiddetto \textit{environment} (cioè l'uso delle
\textsl{variabili di ambiente}). In questa sezione esamineremo le funzioni che
-permettono di gestire parametri ed opzioni, e quelle che consentono di
+permettono di gestire argomenti ed opzioni, e quelle che consentono di
manipolare ed utilizzare le variabili di ambiente.
-\subsection{Il formato dei parametri}
+\subsection{Il formato degli argomenti}
\label{sec:proc_par_format}
-In genere passaggio dei parametri al programma viene effettuato dalla shell,
+In genere passaggio degli argomenti al programma viene effettuato dalla shell,
che si incarica di leggere la linea di comando e di effettuarne la scansione
(il cosiddetto \textit{parsing}) per individuare le parole che la compongono,
-ciascuna delle quali viene considerata un parametro. Di norma per individuare
+ciascuna delle quali viene considerata un argomento. Di norma per individuare
le parole viene usato come carattere di separazione lo spazio o il tabulatore,
ma il comportamento è modificabile attraverso l'impostazione della variabile
di ambiente \cmd{IFS}.
Nella scansione viene costruito il vettore di puntatori \param{argv} inserendo
in successione il puntatore alla stringa costituente l'$n$-simo parametro; la
-variabile \param{argc} viene inizializzata al numero di parametri trovati, in
+variabile \param{argc} viene inizializzata al numero di argomenti trovati, in
questo modo il primo parametro è sempre il nome del programma; un esempio di
questo meccanismo è mostrato in fig.~\ref{fig:proc_argv_argc}.
\textit{environment list}) messa a disposizione dal processo, e costruita
nella chiamata alla funzione \func{exec} quando questo viene lanciato.
-Come per la lista dei parametri anche questa lista è un vettore di puntatori a
-caratteri, ciascuno dei quali punta ad una stringa, terminata da un
+Come per la lista degli argomenti anche questa lista è un vettore di puntatori
+a caratteri, ciascuno dei quali punta ad una stringa, terminata da un
\val{NULL}. A differenza di \code{argv[]} in questo caso non si ha una
lunghezza del vettore data da un equivalente di \param{argc}, ma la lista è
terminata da un puntatore nullo.
Nella maggior parte delle funzioni di libreria e delle system call i puntatori
vengono usati per scambiare dati (attraverso buffer o strutture) e le
-variabili semplici vengono usate per specificare parametri; in genere le
+variabili semplici vengono usate per specificare argomenti; in genere le
informazioni a riguardo dei risultati vengono passate alla routine chiamante
attraverso il valore di ritorno. È buona norma seguire questa pratica anche
nella programmazione normale.
Talvolta però è necessario che la funzione possa restituire indietro alla
-funzione chiamante un valore relativo ad uno dei suoi parametri. Per far
+funzione chiamante un valore relativo ad uno dei suoi argomenti. Per far
questo si usa il cosiddetto
\index{\textit{value~result~argument}}\textit{value result argument}, si passa
cioè, invece di una normale variabile, un puntatore alla stessa; vedremo
\label{sec:proc_variadic}
Come vedremo nei capitoli successivi, non sempre è possibile specificare un
-numero fisso di parametri per una funzione. Lo standard ISO C prevede nella
+numero fisso di argomenti per una funzione. Lo standard ISO C prevede nella
sua sintassi la possibilità di definire delle \textit{variadic
function}\index{variadic} che abbiano un numero variabile di argomenti,
attraverso l'uso della \textit{ellipsis} \code{...} nella dichiarazione della
dichiarazione è il prototipo della funzione \func{execl} che vedremo in
sez.~\ref{sec:proc_exec}:
\includecodesnip{listati/exec_sample.c}
-in questo caso la funzione prende due parametri fissi ed un numero variabile
-di altri parametri (che verranno a costituire gli elementi successivi al primo
+in questo caso la funzione prende due argomenti fissi ed un numero variabile
+di altri argomenti (che verranno a costituire gli elementi successivi al primo
del vettore \param{argv} passato al nuovo processo). Lo standard ISO C richiede
inoltre che l'ultimo degli argomenti fissi sia di tipo
\textit{self-promoting}\footnote{il linguaggio C prevede che quando si
alcuni compilatori è di non dichiarare l'ultimo parametro fisso come
\direct{register}.
-Una volta dichiarata la funzione il secondo passo è accedere ai vari parametri
-quando la si va a definire. I parametri fissi infatti hanno un loro nome, ma
-quelli variabili vengono indicati in maniera generica dalla ellipsis.
+Una volta dichiarata la funzione il secondo passo è accedere ai vari argomenti
+quando la si va a definire. Gli argomenti fissi infatti hanno un loro nome, ma
+quelli variabili vengono indicati in maniera generica dalla \textit{ellipsis}.
L'unica modalità in cui essi possono essere recuperati è pertanto quella
sequenziale; essi verranno estratti dallo stack secondo l'ordine in cui sono
\item Accedere ai vari argomenti opzionali con chiamate successive alla macro
\macro{va\_arg}, la prima chiamata restituirà il primo argomento, la seconda
il secondo e così via.
-\item Dichiarare la conclusione dell'estrazione dei parametri invocando la
+\item Dichiarare la conclusione dell'estrazione degli argomenti invocando la
macro \macro{va\_end}.
\end{enumerate*}
in generale è perfettamente legittimo richiedere meno argomenti di quelli che
\funcdecl{void va\_start(va\_list ap, last)} Inizializza il puntatore alla
lista di argomenti \param{ap}; il parametro \param{last} \emph{deve} essere
- l'ultimo dei parametri fissi.
+ l'ultimo degli argomenti fissi.
\funcdecl{type va\_arg(va\_list ap, type)} Restituisce il valore del
successivo parametro opzionale, modificando opportunamente \param{ap}; la
usato (lo standard richiederebbe la chiamata esplicita di \macro{va\_end}),
dato che il valore di \param{ap} risulterebbe indefinito.
-Esistono dei casi in cui è necessario eseguire più volte la scansione dei
-parametri e poter memorizzare una posizione durante la stessa. La cosa più
+Esistono dei casi in cui è necessario eseguire più volte la scansione degli
+argomenti e poter memorizzare una posizione durante la stessa. La cosa più
naturale in questo caso sembrerebbe quella di copiarsi il puntatore alla lista
degli argomenti con una semplice assegnazione. Dato che una delle
realizzazioni più comuni di \macro{va\_list} è quella di un puntatore nello
-stack all'indirizzo dove sono stati salvati i parametri, è assolutamente
+stack all'indirizzo dove sono stati salvati gli argomenti, è assolutamente
normale pensare di poter effettuare questa operazione.
In generale però possono esistere anche realizzazioni diverse, per questo
La chiamata di una funzione con un numero variabile di argomenti, posto che la
si sia dichiarata e definita come tale, non prevede nulla di particolare;
-l'invocazione è identica alle altre, con i parametri, sia quelli fissi che
+l'invocazione è identica alle altre, con gli argomenti, sia quelli fissi che
quelli opzionali, separati da virgole. Quello che però è necessario tenere
-presente è come verranno convertiti gli argomenti variabili.
+presente è come verranno convertiti gli argomenti variabili.
In Linux gli argomenti dello stesso tipo sono passati allo stesso modo, sia
che siano fissi sia che siano opzionali (alcuni sistemi trattano diversamente
Uno dei problemi che si devono affrontare con le funzioni con un numero
variabile di argomenti è che non esiste un modo generico che permetta di
-stabilire quanti sono i parametri passati effettivamente in una chiamata.
+stabilire quanti sono gli argomenti passati effettivamente in una chiamata.
Esistono varie modalità per affrontare questo problema; una delle più
immediate è quella di specificare il numero degli argomenti opzionali come uno
per specificare anche il tipo degli argomenti (come fa la stringa di formato
per \func{printf}).
-Una modalità diversa, che può essere applicata solo quando il tipo dei
-parametri lo rende possibile, è quella che prevede di usare un valore speciale
+Una modalità diversa, che può essere applicata solo quando il tipo degli
+argomenti lo rende possibile, è quella che prevede di usare un valore speciale
come ultimo argomento (come fa ad esempio \func{execl} che usa un puntatore
\val{NULL} per indicare la fine della lista degli argomenti).
efficiente e più chiara anche dal punto di vista della struttura del
programma: quello dell'uscita in caso di errore.
-Il C però non consente di effettuare un salto ad una etichetta definita in
-un'altra funzione, per cui se l'errore avviene in una funzione, e la sua
-gestione ordinaria è in un'altra, occorre usare quello che viene chiamato un
-\textsl{salto non-locale}\index{salto non-locale}. Il caso classico in cui si
+\index{salto~non-locale|(}
+
+Il C però non consente di effettuare un salto ad
+una etichetta definita in un'altra funzione, per cui se l'errore avviene in
+una funzione, e la sua gestione ordinaria è in un'altra, occorre usare quello
+che viene chiamato un \textsl{salto non-locale}. Il caso classico in cui si
ha questa necessità, citato sia da \cite{APUE} che da \cite{glibc}, è quello
di un programma nel cui corpo principale vengono letti dei dati in ingresso
sui quali viene eseguita, tramite una serie di funzioni di analisi, una
scartando l'input come errato.\footnote{a meno che, come precisa \cite{glibc},
alla chiusura di ciascuna fase non siano associate operazioni di pulizia
specifiche (come deallocazioni, chiusure di file, ecc.), che non potrebbero
- essere eseguite con un salto non-locale\index{salto non-locale}.}
+ essere eseguite con un salto non-locale.}
Tutto ciò può essere realizzato proprio con un salto non-locale; questo di
norma viene realizzato salvando il contesto dello stack nel punto in cui si
Quando viene eseguita direttamente la funzione ritorna sempre zero, un valore
diverso da zero viene restituito solo quando il ritorno è dovuto ad una
chiamata di \func{longjmp} in un'altra parte del programma che ripristina lo
-stack effettuando il salto non-locale\index{salto non-locale}. Si tenga conto
-che il contesto salvato in \param{env} viene invalidato se la routine che ha
-chiamato \func{setjmp} ritorna, nel qual caso un successivo uso di
-\func{longjmp} può comportare conseguenze imprevedibili (e di norma fatali)
-per il processo.
+stack effettuando il salto non-locale. Si tenga conto che il contesto salvato
+in \param{env} viene invalidato se la routine che ha chiamato \func{setjmp}
+ritorna, nel qual caso un successivo uso di \func{longjmp} può comportare
+conseguenze imprevedibili (e di norma fatali) per il processo.
-Come accennato per effettuare un salto non-locale\index{salto non-locale} ad
+Come accennato per effettuare un salto non-locale ad
un punto precedentemente stabilito con \func{setjmp} si usa la funzione
\funcd{longjmp}; il suo prototipo è:
\begin{functions}
ottenuta da un \func{longjmp}, è il valore di ritorno di \func{setjmp}, essa è
usualmente chiamata all'interno di un comando \code{if}.
-Uno dei punti critici dei salti non-locali\index{salto non-locale} è quello
-del valore delle variabili, ed in particolare quello delle variabili
-automatiche della funzione a cui si ritorna. In generale le variabili globali
-e statiche mantengono i valori che avevano al momento della chiamata di
-\func{longjmp}, ma quelli delle variabili automatiche (o di quelle dichiarate
+Uno dei punti critici dei salti non-locali è quello del valore delle
+variabili, ed in particolare quello delle variabili automatiche della funzione
+a cui si ritorna. In generale le variabili globali e statiche mantengono i
+valori che avevano al momento della chiamata di \func{longjmp}, ma quelli
+delle variabili automatiche (o di quelle dichiarate
\direct{register}\footnote{la direttiva \direct{register} del compilatore
chiede che la variabile dichiarata tale sia mantenuta, nei limiti del
possibile, all'interno di un registro del processore. Questa direttiva è
si perderebbero le eventuali modifiche fatte dagli altri programmi (che
avvengono solo in una copia posta in memoria).}.
-
+\index{salto~non-locale|)}
%%% Local Variables:
%%% mode: latex
\end{figure}
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
+\textit{scheduler}\index{\textit{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
parte.} (ma può essere anche attivato esplicitamente). Il timer di sistema
provvede comunque a che esso sia invocato periodicamente, generando un
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
-sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba essere posto in
-esecuzione fino alla successiva invocazione.
+Ogni volta che viene eseguito, lo \textit{scheduler}\index{\textit{scheduler}}
+effettua il calcolo delle priorità dei vari processi attivi (torneremo su
+questo 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}
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 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.
+\acr{pid} per generare un \index{\textit{pathname}}\textit{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
Per quanto riguarda la gestione della memoria, in generale il segmento di
testo, che è identico per i due processi, è condiviso e tenuto in read-only
per il padre e per i figli. Per gli altri segmenti Linux utilizza la tecnica
-del \textit{copy on write}\index{copy on write}; questa tecnica comporta che
-una pagina di memoria viene effettivamente copiata per il nuovo processo solo
-quando ci viene effettuata sopra una scrittura (e si ha quindi una reale
-differenza fra padre e figlio). In questo modo si rende molto più efficiente
-il meccanismo della creazione di un nuovo processo, non essendo più necessaria
-la copia di tutto lo spazio degli indirizzi virtuali del padre, ma solo delle
-pagine di memoria che sono state modificate, e solo al momento della modifica
-stessa.
+del \textit{copy on write}\index{\textit{copy~on~write}}; questa tecnica
+comporta che una pagina di memoria viene effettivamente copiata per il nuovo
+processo solo quando ci viene effettuata sopra una scrittura (e si ha quindi
+una reale differenza fra padre e figlio). In questo modo si rende molto più
+efficiente il meccanismo della creazione di un nuovo processo, non essendo più
+necessaria la copia di tutto lo spazio degli indirizzi virtuali del padre, ma
+solo delle pagine di memoria che sono state modificate, e solo al momento
+della modifica stessa.
La differenza che si ha nei due processi è che nel processo padre il valore di
ritorno della funzione \func{fork} è il \acr{pid} del processo figlio, mentre
Esaminiamo questo risultato: una prima conclusione che si può trarre è che non
si può dire quale processo fra il padre ed il figlio venga eseguito per
primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo
- scheduler\index{scheduler} di Ingo Molnar che esegue sempre per primo il
- figlio; per mantenere la portabilità è opportuno non fare comunque
+ scheduler\index{\textit{scheduler}} di Ingo Molnar che esegue sempre per
+ primo il figlio; per mantenere la portabilità è opportuno non fare comunque
affidamento su questo comportamento.} dopo la chiamata a \func{fork};
dall'esempio si può notare infatti come nei primi due cicli sia stato eseguito
per primo il padre (con la stampa del \acr{pid} del nuovo processo) per poi
essere messi in esecuzione. Se è necessaria una qualche forma di precedenza
occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il
rischio di incorrere nelle cosiddette
-\textit{race condition}\index{race condition}
+\textit{race condition}\index{\textit{race~condition}}
(vedi sez.~\ref{sec:proc_race_cond}).
Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
comune dopo l'esecuzione di una \func{fork} è la seguente:
\begin{itemize*}
\item i file aperti e gli eventuali flag di
- \textit{close-on-exec}\index{close-on-exec} impostati (vedi
+ \textit{close-on-exec}\index{\textit{close-on-exec}} impostati (vedi
sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}).
\item gli identificatori per il controllo di accesso: l'\textsl{user-ID
reale}, il \textsl{group-ID reale}, l'\textsl{user-ID effettivo}, il
\func{fork} veniva fatta solo per poi eseguire una \func{exec}. La funzione
venne introdotta in BSD per migliorare le prestazioni.
-Dato che Linux supporta il \textit{copy on write}\index{copy on write} la
-perdita di prestazioni è assolutamente trascurabile, e l'uso di questa
-funzione (che resta un caso speciale della system call \func{\_\_clone}), è
-deprecato; per questo eviteremo di trattarla ulteriormente.
+Dato che Linux supporta il \textit{copy on
+ write}\index{\textit{copy~on~write}} la perdita di prestazioni è
+assolutamente trascurabile, e l'uso di questa funzione (che resta un caso
+speciale della system call \func{\_\_clone}), è deprecato; per questo
+eviteremo di trattarla ulteriormente.
\subsection{La conclusione di un processo.}
Le altre quattro funzioni si limitano invece a cercare di eseguire il file
indicato dall'argomento \param{path}, che viene interpretato come il
-\textit{pathname} del programma.
+\index{\textit{pathname}}\textit{pathname} del programma.
\begin{figure}[htb]
\centering
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
+\textit{close-on-exec}\index{\textit{close-on-exec}} (vedi anche
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
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 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.
+l'impostazione del flag di
+\textit{close-on-exec}\index{\textit{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
\label{sec:proc_priority}
In questa sezione tratteremo più approfonditamente i meccanismi con il quale
-lo \textit{scheduler}\index{scheduler} assegna la CPU ai vari processi attivi.
-In particolare prenderemo in esame i vari meccanismi con cui viene gestita
-l'assegnazione del tempo di CPU, ed illustreremo le varie funzioni di
-gestione.
+lo \textit{scheduler}\index{\textit{scheduler}} assegna la CPU ai vari
+processi attivi. In particolare prenderemo in esame i vari meccanismi con cui
+viene gestita l'assegnazione del tempo di CPU, ed illustreremo le varie
+funzioni di gestione.
\subsection{I meccanismi di \textit{scheduling}}
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
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.
+apposita del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, il cui
+scopo è quello di 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 deve anche scegliere quale sia la CPU più opportuna da
il processo viene eseguito per la prima volta e diminuito progressivamente ad
ogni interruzione del timer.
-Durante la sua esecuzione lo scheduler\index{scheduler} scandisce la coda dei
-processi in stato \textit{runnable} associando, in base al valore di
+Durante la sua esecuzione lo scheduler\index{\textit{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 eseguito sulla stessa CPU, e a
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
+page fault\index{\textit{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 sez.~\ref{sec:proc_mem_lock}), il primo
non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di
esecuzione di qualunque processo.
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
-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:
+Quando c'è un processo con priorità assoluta lo
+scheduler\index{\textit{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 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{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
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
+\textit{race condition}\index{\textit{race~condition}} (vedi
sez.~\ref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase
in cui non erano ancora state completate.
-\subsection{Le \textit{race condition}\index{race condition} e i
- \textit{deadlock}\index{deadlock}}
+\subsection{Le \textit{race condition} ed i \textit{deadlock}}
\label{sec:proc_race_cond}
-Si definiscono \textit{race condition}\index{race condition} tutte quelle
-situazioni in cui processi diversi operano su una risorsa comune, ed in cui il
-risultato viene a dipendere dall'ordine in cui essi effettuano le loro
-operazioni. Il caso tipico è quello di un'operazione che viene eseguita da un
-processo in più passi, e può essere compromessa dall'intervento di un altro
-processo che accede alla stessa risorsa quando ancora non tutti i passi sono
-stati completati.
+\index{\textit{race~condition}|(}
+Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
+diversi operano su una risorsa comune, ed in cui il risultato viene a
+dipendere dall'ordine in cui essi effettuano le loro operazioni. Il caso
+tipico è quello di un'operazione che viene eseguita da un processo in più
+passi, e può essere compromessa dall'intervento di un altro 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ò
Per questo occorre essere ben consapevoli di queste problematiche, e del fatto
che l'unico modo per evitarle è quello di riconoscerle come tali e prendere
gli adeguati provvedimenti per far sì che non si verifichino. Casi tipici di
-\textit{race condition}\index{race condition} si hanno quando diversi processi
-accedono allo stesso file, o nell'accesso a meccanismi di intercomunicazione
-come la memoria condivisa. In questi casi, se non si dispone della possibilità
-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
+\textit{race condition} si hanno quando diversi processi accedono allo stesso
+file, o nell'accesso a meccanismi di intercomunicazione come la memoria
+condivisa. In questi casi, se non si dispone della possibilità 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 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
-quanto comportano spesso il blocco completo di un servizio, e non il
-fallimento di una singola operazione. Per definizione un
-\textit{deadlock}\index{deadlock} è una situazione in cui due o più processi
+\index{\textit{deadlock}|(}
+Un caso particolare di \textit{race condition} sono poi i cosiddetti
+\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
+completo di un servizio, e non il fallimento di una singola operazione. Per
+definizione un \textit{deadlock} è una situazione in cui due o più processi
non sono più in grado di proseguire perché ciascuno aspetta il risultato di
una operazione che dovrebbe essere eseguita dall'altro.
L'esempio tipico di una situazione che può condurre ad un
-\textit{deadlock}\index{deadlock} è quello in cui un flag di
+\textit{deadlock} è quello in cui un flag di
``\textsl{occupazione}'' viene rilasciato da un evento asincrono (come un
segnale o un altro processo) fra il momento in cui lo si è controllato
(trovandolo occupato) e la successiva operazione di attesa per lo sblocco. In
questo caso, dato che l'evento di sblocco del flag è avvenuto senza che ce ne
accorgessimo proprio fra il controllo e la messa in attesa, quest'ultima
-diventerà perpetua (da cui il nome di \textit{deadlock}\index{deadlock}).
+diventerà perpetua (da cui il nome di \textit{deadlock}).
In tutti questi casi è di fondamentale importanza il concetto di atomicità
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.
+\index{\textit{race~condition}|)}
+\index{\textit{deadlock}|)}
\subsection{Le funzioni rientranti}
per entrambi; una delle due chiamate sarà ridondante, ma non potendo
determinare quale dei due processi viene eseguito per primo, occorre eseguirle
comunque entrambe per evitare di esporsi ad una race
-condition\index{race condition}.
+condition\index{\textit{race~condition}}.
Si noti come nessuna delle funzioni esaminate finora permetta di spostare un
processo da una sessione ad un altra; infatti l'unico modo di far cambiare
Restituisce il nome del terminale di controllo del processo.
\bodydesc{La funzione restituisce il puntatore alla stringa contenente il
- pathname del terminale.}
+ \textit{pathname} del terminale.}
\end{prototype}
-La funzione scrive il pathname del terminale di controllo del processo
-chiamante nella stringa posta all'indirizzo specificato dall'argomento
-\param{s}. La memoria per contenere la stringa deve essere stata allocata in
-precedenza ed essere lunga almeno
+La funzione scrive il \index{\textit{pathname}}\textit{pathname} del terminale
+di controllo del processo chiamante nella stringa posta all'indirizzo
+specificato dall'argomento \param{s}. La memoria per contenere la stringa
+deve essere stata allocata in precedenza ed essere lunga almeno
\const{L\_ctermid}\footnote{\const{L\_ctermid} è una delle varie costanti del
sistema, non trattata esplicitamente in sez.~\ref{sec:sys_characteristics}
che indica la dimensione che deve avere una stringa per poter contenere il
\param{len}; se la stringa che deve essere restituita eccede questa dimensione
si avrà una condizione di errore.
-Se si passa come argomento \val{NULL} la funzione restituisce il puntatore
-ad una stringa statica che può essere sovrascritta da chiamate successive. Si
-tenga presente che il pathname restituito potrebbe non identificare
-univocamente il terminale (ad esempio potrebbe essere \file{/dev/tty}),
-inoltre non è detto che il processo possa effettivamente aprire il terminale.
+Se si passa come argomento \val{NULL} la funzione restituisce il puntatore ad
+una stringa statica che può essere sovrascritta da chiamate successive. Si
+tenga presente che il \index{\textit{pathname}}\textit{pathname} restituito
+potrebbe non identificare univocamente il terminale (ad esempio potrebbe
+essere \file{/dev/tty}), inoltre non è detto che il processo possa
+effettivamente aprire il terminale.
I vari attributi vengono mantenuti per ciascun terminale in una struttura
\struct{termios}, (la cui definizione è riportata in
Questa è la ragione per cui l'implementazione dei segnali secondo questa
semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del
-segnale e la reinstallazione del suo gestore non sono operazioni
-atomiche, e sono sempre possibili delle race condition\index{race condition}
+segnale e la reinstallazione del suo gestore non sono operazioni atomiche, e
+sono sempre possibili delle race condition\index{\textit{race~condition}}
(sull'argomento vedi quanto detto in sez.~\ref{sec:proc_multi_prog}).
Un'altro problema è che in questa semantica non esiste un modo per bloccare i
\textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre
per tutto il tempo che passa fra la generazione del segnale e la sua consegna
esso è detto \textsl{pendente} (o \textit{pending}). In genere questa
-procedura viene effettuata dallo scheduler\index{scheduler} quando,
+procedura viene effettuata dallo scheduler\index{\textit{scheduler}} quando,
riprendendo l'esecuzione del processo in questione, verifica la presenza del
segnale nella \struct{task\_struct} e mette in esecuzione il gestore.
Normalmente l'invio al processo che deve ricevere il segnale è immediato ed
avviene non appena questo viene rimesso in esecuzione dallo
-scheduler\index{scheduler} che esegue l'azione specificata. Questo a meno che
-il segnale in questione non sia stato bloccato prima della notifica, nel qual
-caso l'invio non avviene ed il segnale resta \textsl{pendente}
+scheduler\index{\textit{scheduler}} che esegue l'azione specificata. Questo a
+meno che il segnale in questione non sia stato bloccato prima della notifica,
+nel qual caso l'invio non avviene ed il segnale resta \textsl{pendente}
indefinitamente. Quando lo si sblocca il segnale \textsl{pendente} sarà subito
notificato. Si tenga presente però che i segnali \textsl{pendenti} non si
accodano, alla generazione infatti il kernel marca un flag nella
quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema
farà si che mentre viene eseguito il gestore di un segnale, quest'ultimo
venga automaticamente bloccato (così si possono evitare race
-condition\index{race condition}).
+condition\index{\textit{race~condition}}).
Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
standard che (come vedremo in sez.~\ref{sec:sig_standard}) è propria di ciascun
successiva pressione di \texttt{C-c} o \texttt{C-y}.
Per quanto riguarda il comportamento di tutte le altre system call si danno
-sostanzialmente due casi, a seconda che esse siano\index{system call lente}
+sostanzialmente due casi, a seconda che esse siano\index{system~call~lente}
\textsl{lente} (\textit{slow}) o \textsl{veloci} (\textit{fast}). La gran
parte di esse appartiene a quest'ultima categoria, che non è influenzata
dall'arrivo di un segnale. Esse sono dette \textsl{veloci} in quanto la loro
presenta questa situazione è il seguente:
\begin{itemize*}
\item la lettura da file che possono bloccarsi in attesa di dati non ancora
- presenti (come per certi file di dispositivo\index{file!di dispositivo}, i
+ presenti (come per certi file di dispositivo\index{file!di~dispositivo}, i
socket\index{socket} o le pipe).
\item la scrittura sugli stessi file, nel caso in cui dati non possano essere
accettati immediatamente.
nanosecondo, la precisione di \func{nanosleep} è determinata dalla risoluzione
temporale del timer di sistema. Perciò la funzione attenderà comunque il tempo
specificato, ma prima che il processo possa tornare ad essere eseguito
-occorrerà almeno attendere il successivo giro di scheduler\index{scheduler} e
-cioè un tempo che a seconda dei casi può arrivare fino a 1/\const{HZ}, (sempre
-che il sistema sia scarico ed il processa venga immediatamente rimesso in
-esecuzione); per questo motivo il valore restituito in \param{rem} è sempre
-arrotondato al multiplo successivo di 1/\const{HZ}.
+occorrerà almeno attendere il successivo giro di
+scheduler\index{\textit{scheduler}} e cioè un tempo che a seconda dei casi può
+arrivare fino a 1/\const{HZ}, (sempre che il sistema sia scarico ed il
+processa venga immediatamente rimesso in esecuzione); per questo motivo il
+valore restituito in \param{rem} è sempre arrotondato al multiplo successivo
+di 1/\const{HZ}.
In realtà è possibile ottenere anche pause più precise del centesimo di
secondo usando politiche di scheduling real time come \const{SCHED\_FIFO} o
Le funzioni esaminate finora fanno riferimento ad alle modalità più elementari
della gestione dei segnali; non si sono pertanto ancora prese in
considerazione le tematiche più complesse, collegate alle varie race
-condition\index{race condition} che i segnali possono generare e alla natura
-asincrona degli stessi.
+condition\index{\textit{race~condition}} che i segnali possono generare e alla
+natura asincrona degli stessi.
Affronteremo queste problematiche in questa sezione, partendo da un esempio
che le evidenzi, per poi prendere in esame le varie funzioni che permettono di
Questo codice però, a parte il non gestire il caso in cui si è avuta una
precedente chiamata a \func{alarm} (che si è tralasciato per brevità),
-presenta una pericolosa race condition\index{race condition}. Infatti se il
-processo viene interrotto fra la chiamata di \func{alarm} e \func{pause} può
-capitare (ad esempio se il sistema è molto carico) che il tempo di attesa
-scada prima dell'esecuzione quest'ultima, cosicché essa sarebbe eseguita dopo
-l'arrivo di \const{SIGALRM}. In questo caso ci si troverebbe di fronte ad un
-deadlock\index{deadlock}, in quanto \func{pause} non verrebbe mai più
-interrotta (se non in caso di un altro segnale).
+presenta una pericolosa race condition\index{\textit{race~condition}}.
+Infatti se il processo viene interrotto fra la chiamata di \func{alarm} e
+\func{pause} può capitare (ad esempio se il sistema è molto carico) che il
+tempo di attesa scada prima dell'esecuzione quest'ultima, cosicché essa
+sarebbe eseguita dopo l'arrivo di \const{SIGALRM}. In questo caso ci si
+troverebbe di fronte ad un deadlock\index{\textit{deadlock}}, in quanto
+\func{pause} non verrebbe mai più interrotta (se non in caso di un altro
+segnale).
Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
SVr2) usando la funzione \func{longjmp} (vedi sez.~\ref{sec:proc_longjmp}) per
segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}).
Questo è il tipico esempio di caso, già citato in
-sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition
-\index{race condition}; se infatti il segnale arriva immediatamente dopo
-l'esecuzione del controllo (\texttt{\small 6}) ma prima della cancellazione
-del flag (\texttt{\small 7}), la sua occorrenza sarà perduta.
+sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition
+\index{\textit{race~condition}}; se infatti il segnale arriva immediatamente
+dopo l'esecuzione del controllo (\texttt{\small 6}) ma prima della
+cancellazione del flag (\texttt{\small 7}), la sua occorrenza sarà perduta.
Questi esempi ci mostrano che per una gestione effettiva dei segnali occorrono
funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla
\subsection{Gli \textsl{insiemi di segnali} o \textit{signal set}}
\label{sec:sig_sigset}
+\index{\textit{signal~set}|(}
Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali
originarie, nate con la semantica inaffidabile, hanno dei limiti non
superabili; in particolare non è prevista nessuna funzione che permetta di
dei segnali ha introdotto una interfaccia di gestione completamente nuova, che
permette di ottenete un controllo molto più dettagliato. In particolare lo
standard ha introdotto un nuovo tipo di dato \type{sigset\_t}, che permette di
-rappresentare un \textsl{insieme di segnali} (un
-\index{\textit{signal set}}\textit{signal set}, come viene usualmente
-chiamato), che è il tipo di dato che viene usato per gestire il blocco dei
-segnali.
+rappresentare un \textsl{insieme di segnali} (un \textit{signal set}, come
+viene usualmente chiamato), che è il tipo di dato che viene usato per gestire
+il blocco dei segnali.
In genere un \textsl{insieme di segnali} è rappresentato da un intero di
dimensione opportuna, di solito si pari al numero di bit dell'architettura
insieme completo ottenuto con \func{sigfillset}. Infine \func{sigismember}
permette di verificare la presenza di uno specifico segnale in un
insieme.
+\index{\textit{signal~set}|)}
+
\subsection{La funzione \func{sigaction}}
\const{SA\_RESTART} & Riavvia automaticamente le \textit{slow system
call} quando vengono interrotte dal suddetto
segnale; riproduce cioè il comportamento standard
- di BSD.\index{system call lente}\\
+ di BSD.\index{system~call~lente}\\
\const{SA\_NOMASK} & Evita che il segnale corrente sia bloccato durante
l'esecuzione del gestore.\\
\const{SA\_NODEFER} & Sinonimo di \const{SA\_NOMASK}.\\
\textit{signal mask}}
\label{sec:sig_sigmask}
+\index{\textit{signal mask}|(}
Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like
permettono si bloccare temporaneamente (o di eliminare completamente,
impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un
perduta alla conclusione del terminatore.
Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte
-dei casi di race condition\index{race condition} restano aperte alcune
-possibilità legate all'uso di \func{pause}; il caso è simile a quello del
-problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e cioè
-la possibilità che il processo riceva il segnale che si intende usare per
+dei casi di race condition\index{\textit{race~condition}} restano aperte
+alcune possibilità legate all'uso di \func{pause}; il caso è simile a quello
+del problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e
+cioè la possibilità che il processo riceva il segnale che si intende usare per
uscire dallo stato di attesa invocato con \func{pause} immediatamente prima
dell'esecuzione di quest'ultima. Per poter effettuare atomicamente la modifica
della maschera dei segnali (di solito attivandone uno specifico) insieme alla
\var{sleep\_mask} per riattivare \const{SIGALRM} all'esecuzione di
\func{sigsuspend}.
-In questo modo non sono più possibili race condition\index{race condition}
-dato che \const{SIGALRM} viene disabilitato con \func{sigprocmask} fino alla
-chiamata di \func{sigsuspend}. Questo metodo è assolutamente generale e può
-essere applicato a qualunque altra situazione in cui si deve attendere per un
-segnale, i passi sono sempre i seguenti:
+In questo modo non sono più possibili race
+condition\index{\textit{race~condition}} dato che \const{SIGALRM} viene
+disabilitato con \func{sigprocmask} fino alla chiamata di \func{sigsuspend}.
+Questo metodo è assolutamente generale e può essere applicato a qualunque
+altra situazione in cui si deve attendere per un segnale, i passi sono sempre
+i seguenti:
\begin{enumerate*}
\item Leggere la maschera dei segnali corrente e bloccare il segnale voluto
con \func{sigprocmask}.
\end{enumerate*}
Per quanto possa sembrare strano bloccare la ricezione di un segnale per poi
riabilitarla immediatamente dopo, in questo modo si evita il
-deadlock\index{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione
-di \func{sigsuspend}.
+deadlock\index{\textit{deadlock}} dovuto all'arrivo del segnale prima
+dell'esecuzione di \func{sigsuspend}.
+\index{\textit{signal mask}|)}
\subsection{Ulteriori funzioni di gestione}
\headdecl{setjmp.h}
\funcdecl{int sigsetjmp(sigjmp\_buf env, int savesigs)} Salva il contesto
- dello stack per un salto non-locale\index{salto non-locale}.
+ dello stack per un salto non-locale\index{salto~non-locale}.
\funcdecl{void siglongjmp(sigjmp\_buf env, int val)} Esegue un salto
non-locale su un precedente contesto.
Le due funzioni prendono come primo argomento la variabile su cui viene
salvato il contesto dello stack per permettere il salto non-locale
-\index{salto non-locale}; nel caso specifico essa è di tipo
+\index{salto~non-locale}; nel caso specifico essa è di tipo
\type{sigjmp\_buf}, e non \type{jmp\_buf} come per le analoghe di
sez.~\ref{sec:proc_longjmp} in quanto in questo caso viene salvata anche la
maschera dei segnali.
\subsection{La struttura del \textit{resolver}}
\label{sec:sock_resolver}
+\index{\textit{resolver}|(}
La risoluzione dei nomi è associata tradizionalmente al servizio del
\textit{Domain Name Service} che permette di identificare le macchine su
internet invece che per numero IP attraverso il relativo \textsl{nome a
\noindent che, come l'analoga \func{strerror}, restituisce una stringa con un
messaggio di errore già formattato, corrispondente al codice passato come
argomento (che si presume sia dato da \var{h\_errno}).
+\index{\textit{resolver}|)}
\subsection{La risoluzione dei nomi a dominio}
\label{sec:sock_name_services}
-La principale funzionalità del \textit{resolver} resta quella di risolvere i
-nomi a dominio in indirizzi IP, per cui non ci dedicheremo oltre alle funzioni
-di richiesta generica ed esamineremo invece le funzioni a questo dedicate. La
-prima funzione è \funcd{gethostbyname} il cui scopo è ottenere l'indirizzo di
-una stazione noto il suo nome a dominio, il suo prototipo è:
+La principale funzionalità del \index{\textit{resolver}}\textit{resolver}
+resta quella di risolvere i nomi a dominio in indirizzi IP, per cui non ci
+dedicheremo oltre alle funzioni di richiesta generica ed esamineremo invece le
+funzioni a questo dedicate. La prima funzione è \funcd{gethostbyname} il cui
+scopo è ottenere l'indirizzo di una stazione noto il suo nome a dominio, il
+suo prototipo è:
\begin{prototype}{netdb.h}
{struct hostent *gethostbyname(const char *name)}
IPv4, se si vogliono ottenere degli indirizzi IPv6 occorrerà prima impostare
l'opzione \const{RES\_USE\_INET6} nel campo \texttt{\_res.options} e poi
chiamare \func{res\_init} (vedi sez.~\ref{sec:sock_resolver_functions}) per
-modificare le opzioni del resolver; dato che questo non è molto comodo è stata
-definita\footnote{questa è una estensione fornita dalle \acr{glibc},
- disponibile anche in altri sistemi unix-like.} un'altra funzione,
-\funcd{gethostbyname2}, il cui prototipo è:
+modificare le opzioni del \index{\textit{resolver}}\textit{resolver}; dato che
+questo non è molto comodo è stata definita\footnote{questa è una estensione
+ fornita dalle \acr{glibc}, disponibile anche in altri sistemi unix-like.}
+un'altra funzione, \funcd{gethostbyname2}, il cui prototipo è:
\begin{functions}
\headdecl{netdb.h}
\headdecl{sys/socket.h}
Vediamo allora un primo esempio dell'uso delle funzioni di risoluzione, in
fig.~\ref{fig:mygethost_example} è riportato un estratto del codice di un
-programma che esegue una semplice interrogazione al \textit{resolver} usando
-\func{gethostbyname} e poi ne stampa a video i risultati. Al solito il
-sorgente completo, che comprende il trattamento delle opzioni ed una funzione
-per stampare un messaggio di aiuto, è nel file \texttt{mygethost.c} dei
-sorgenti allegati alla guida.
+programma che esegue una semplice interrogazione al
+\index{\textit{resolver}}\textit{resolver} usando \func{gethostbyname} e poi
+ne stampa a video i risultati. Al solito il sorgente completo, che comprende
+il trattamento delle opzioni ed una funzione per stampare un messaggio di
+aiuto, è nel file \texttt{mygethost.c} dei sorgenti allegati alla guida.
Il programma richiede un solo argomento che specifichi il nome da cercare,
senza il quale (\texttt{\small 12--15}) esce con un errore. Dopo di che
\end{figure}
Come primo esempio di uso di \func{getaddrinfo} vediamo un programma
-elementare di interrogazione del resolver basato questa funzione, il cui corpo
-principale è riportato in fig.~\ref{fig:mygetaddr_example}. Il codice completo
-del programma, compresa la gestione delle opzioni in cui è gestita l'eventuale
-inizializzazione dell'argomento \var{hints} per restringere le ricerche su
-protocolli, tipi di socket o famiglie di indirizzi, è disponibile nel file
-\texttt{mygetaddr.c} dei sorgenti allegati alla guida.
+elementare di interrogazione del \index{\textit{resolver}}\textit{resolver}
+basato questa funzione, il cui corpo principale è riportato in
+fig.~\ref{fig:mygetaddr_example}. Il codice completo del programma, compresa
+la gestione delle opzioni in cui è gestita l'eventuale inizializzazione
+dell'argomento \var{hints} per restringere le ricerche su protocolli, tipi di
+socket o famiglie di indirizzi, è disponibile nel file \texttt{mygetaddr.c}
+dei sorgenti allegati alla guida.
\begin{figure}[!htb]
\footnotesize \centering
può essere un file (di tipo socket) nel filesystem o una stringa univoca
(mantenuta in uno spazio di nomi astratto). Nel primo caso l'indirizzo viene
specificato come una stringa (terminata da uno zero) corrispondente al
-pathname del file; nel secondo invece \var{sun\_path} inizia con uno zero e
-vengono usati come nome i restanti byte come stringa, senza terminazione.
+\index{\textit{pathname}}\textit{pathname} del file; nel secondo invece
+\var{sun\_path} inizia con uno zero e vengono usati come nome i restanti byte
+come stringa, senza terminazione.
\subsection{La struttura degli indirizzi AppleTalk}
seguito.
-\subsection{La \textit{endianess}\index{endianess}}
+\subsection{La \textit{endianess}}
\label{sec:sock_endianess}
+\index{\textit{endianess}|(}
La rappresentazione di un numero binario in un computer può essere fatta in
due modi, chiamati rispettivamente \textit{big endian} e \textit{little
endian} a seconda di come i singoli bit vengono aggregati per formare le
\centering
\includegraphics[height=3cm]{img/endianess}
\caption{Schema della disposizione dei dati in memoria a seconda della
- \textit{endianess}\index{endianess}.}
+ \textit{endianess}.}
\label{fig:sock_endianess}
\end{figure}
-Si può allora verificare quale tipo di endianess usa il proprio computer con
-un programma elementare che si limita ad assegnare un valore ad una variabile
-per poi ristamparne il contenuto leggendolo un byte alla volta. Il codice di
-detto programma, \file{endtest.c}, è nei sorgenti allegati, allora se lo
-eseguiamo su un PC otterremo:
+Si può allora verificare quale tipo di \textit{endianess} usa il proprio
+computer con un programma elementare che si limita ad assegnare un valore ad
+una variabile per poi ristamparne il contenuto leggendolo un byte alla volta.
+Il codice di detto programma, \file{endtest.c}, è nei sorgenti allegati,
+allora se lo eseguiamo su un PC otterremo:
\begin{verbatim}
[piccardi@gont sources]$ ./endtest
Using value ABCDEF01
\end{verbatim}%$
-La \textit{endianess}\index{endianess} di un computer dipende essenzialmente
-dalla architettura hardware usata; Intel e Digital usano il \textit{little
- endian}, Motorola, IBM, Sun (sostanzialmente tutti gli altri) usano il
-\textit{big endian}. Il formato dei dati contenuti nelle intestazioni dei
-protocolli di rete è anch'esso \textit{big endian}; altri esempi di uso di
-questi due diversi formati sono quello del bus PCI, che è \textit{little
- endian}, o quello del bus VME che è \textit{big endian}.
+La \textit{endianess} di un computer dipende essenzialmente dalla architettura
+hardware usata; Intel e Digital usano il \textit{little endian}, Motorola,
+IBM, Sun (sostanzialmente tutti gli altri) usano il \textit{big endian}. Il
+formato dei dati contenuti nelle intestazioni dei protocolli di rete è
+anch'esso \textit{big endian}; altri esempi di uso di questi due diversi
+formati sono quello del bus PCI, che è \textit{little endian}, o quello del
+bus VME che è \textit{big endian}.
Esistono poi anche dei processori che possono scegliere il tipo di formato
all'avvio e alcuni che, come il PowerPC o l'Intel i860, possono pure passare
\textit{little endian}). Infine la funzione restituisce (\texttt{\small 12})
il valore del confonto delle due variabili.
+\index{\textit{endianess}|)}
\subsection{Le funzioni per il riordinamento}
\label{sec:sock_func_ord}
-Il problema connesso all'endianess\index{endianess} è che quando si passano
-dei dati da un tipo di architettura all'altra i dati vengono interpretati in
-maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci si ritroverà
-con i due byte in cui è suddiviso scambiati di posto. Per questo motivo si
-usano delle funzioni di conversione che servono a tener conto automaticamente
-della possibile differenza fra l'ordinamento usato sul computer e quello che
-viene usato nelle trasmissione sulla rete; queste funzioni sono \funcd{htonl},
-\funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i rispettivi prototipi sono:
+Il problema connesso all'endianess\index{\textit{endianess}} è che quando si
+passano dei dati da un tipo di architettura all'altra i dati vengono
+interpretati in maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci
+si ritroverà con i due byte in cui è suddiviso scambiati di posto. Per questo
+motivo si usano delle funzioni di conversione che servono a tener conto
+automaticamente della possibile differenza fra l'ordinamento usato sul
+computer e quello che viene usato nelle trasmissione sulla rete; queste
+funzioni sono \funcd{htonl}, \funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i
+rispettivi prototipi sono:
\begin{functions}
\headdecl{netinet/in.h}
\funcdecl{unsigned long int htonl(unsigned long int hostlong)}
\hline
\const{LINK\_MAX} &8 & numero massimo di link a un file\\
\const{NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\
- \const{PATH\_MAX}& 256 & lunghezza in byte di un pathname.\\
+ \const{PATH\_MAX}& 256 & lunghezza in byte di un
+ \index{\textit{pathname}}\textit{pathname}.\\
\const{PIPE\_BUF}&4096 & byte scrivibili atomicamente in una pipe
(vedi sez.~\ref{sec:ipc_pipes}).\\
\const{MAX\_CANON}&255 & dimensione di una riga di terminale in modo
\hline
\const{\_POSIX\_LINK\_MAX} &8 & numero massimo di link a un file.\\
\const{\_POSIX\_NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\
- \const{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di un pathname.\\
+ \const{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di un
+ \index{\textit{pathname}}\textit{pathname}.\\
\const{\_POSIX\_PIPE\_BUF}& 512 & byte scrivibili atomicamente in una
- pipe.\\
+ pipe.\\
\const{\_POSIX\_MAX\_CANON}&255 & dimensione di una riga di
- terminale in modo canonico.\\
+ terminale in modo canonico.\\
\const{\_POSIX\_MAX\_INPUT}&255 & spazio disponibile nella coda di input
- del terminale.\\
+ del terminale.\\
% \const{\_POSIX\_MQ\_OPEN\_MAX}& 8& \\
% \const{\_POSIX\_MQ\_PRIO\_MAX}& 32& \\
% \const{\_POSIX\_FD\_SETSIZE}& 16 & \\
E si noti come la funzione in questo caso richieda un parametro che specifichi
a quale file si fa riferimento, dato che il valore del limite cercato può
variare a seconda del filesystem. Una seconda versione della funzione,
-\funcd{fpathconf}, opera su un file descriptor invece che su un pathname. Il
-suo prototipo è:
+\funcd{fpathconf}, opera su un file descriptor invece che su un
+\index{\textit{pathname}}\textit{pathname}. Il suo prototipo è:
\begin{prototype}{unistd.h}{long fpathconf(int fd, int name)}
Restituisce il valore del parametro \param{name} per il file \param{fd}.
\bodydesc{È identica a \func{pathconf} solo che utilizza un file descriptor
- invece di un pathname; pertanto gli errori restituiti cambiano di
- conseguenza.}
+ invece di un \index{\textit{pathname}}\textit{pathname}; pertanto gli
+ errori restituiti cambiano di conseguenza.}
\end{prototype}
\noindent ed il suo comportamento è identico a quello di \func{pathconf}.
occorrerà includere anche i file \file{linux/unistd.h} e
\file{linux/sysctl.h}.} per accedere ad uno di essi occorre specificare un
cammino attraverso i vari nodi dell'albero, in maniera analoga a come avviene
-per la risoluzione di un pathname (da cui l'uso alternativo del filesystem
-\file{/proc}, che vedremo dopo).
+per la risoluzione di un \index{\textit{pathname}}\textit{pathname} (da cui
+l'uso alternativo del filesystem \file{/proc}, che vedremo dopo).
Ciascun nodo dell'albero è identificato da un valore intero, ed il cammino che
arriva ad identificare un parametro specifico è passato alla funzione
In particolare l'albero dei valori di \func{sysctl} viene presentato in forma
di file nella directory \file{/proc/sys}, cosicché è possibile accedervi
-specificando un pathname e leggendo e scrivendo sul file corrispondente al
-parametro scelto. Il kernel si occupa di generare al volo il contenuto ed i
-nomi dei file corrispondenti, e questo ha il grande vantaggio di rendere
-accessibili i vari parametri a qualunque comando di shell e di permettere la
-navigazione dell'albero dei valori.
+specificando un \index{\textit{pathname}}\textit{pathname} e leggendo e
+scrivendo sul file corrispondente al parametro scelto. Il kernel si occupa di
+generare al volo il contenuto ed i nomi dei file corrispondenti, e questo ha
+il grande vantaggio di rendere accessibili i vari parametri a qualunque
+comando di shell e di permettere la navigazione dell'albero dei valori.
Alcune delle corrispondenze dei file presenti in \file{/proc/sys} con i valori
di \func{sysctl} sono riportate nei commenti del codice che può essere trovato
\textit{mount point} o di spostarlo quando \param{target} non è un
\textit{mount point} o è \file{/}.
\item[\errcode{EACCES}] non si ha il permesso di accesso su uno dei
- componenti del pathname, o si è cercato di montare un filesystem
- disponibile in sola lettura senza averlo specificato o il device
- \param{source} è su un filesystem montato con l'opzione \const{MS\_NODEV}.
+ componenti del \index{\textit{pathname}}\textit{pathname}, o si è cercato
+ di montare un filesystem disponibile in sola lettura senza averlo
+ specificato o il device \param{source} è su un filesystem montato con
+ l'opzione \const{MS\_NODEV}.
\item[\errcode{ENXIO}] il \textit{major number} del device \param{source} è
sbagliato.
\item[\errcode{EMFILE}] la tabella dei device \textit{dummy} è piena.
kernel nelle system call eseguite per conto del processo.
Gli altri tre campi servono a quantificare l'uso della memoria
-virtuale\index{memoria virtuale} e corrispondono rispettivamente al numero di
-\textit{page fault}\index{page fault} (vedi sez.~\ref{sec:proc_mem_gen})
-avvenuti senza richiedere I/O su disco (i cosiddetti \textit{minor page
- fault}), a quelli che invece han richiesto I/O su disco (detti invece
-\textit{major page fault}) ed al numero di volte che il processo è stato
-completamente tolto dalla memoria per essere inserito nello swap.
+virtuale\index{memoria~virtuale} e corrispondono rispettivamente al numero di
+\textit{page fault}\index{\textit{page~fault}} (vedi
+sez.~\ref{sec:proc_mem_gen}) avvenuti senza richiedere I/O su disco (i
+cosiddetti \textit{minor page fault}), a quelli che invece han richiesto I/O
+su disco (detti invece \textit{major page fault}) ed al numero di volte che il
+processo è stato completamente tolto dalla memoria per essere inserito nello
+swap.
In genere includere esplicitamente \file{<sys/time.h>} non è più strettamente
necessario, ma aumenta la portabilità, e serve comunque quando, come nella
La gestione della memoria è già stata affrontata in dettaglio in
sez.~\ref{sec:proc_memory}; abbiamo visto allora che il kernel provvede il
-meccanismo della memoria virtuale\index{memoria virtuale} attraverso la
+meccanismo della memoria virtuale\index{memoria~virtuale} attraverso la
divisione della memoria fisica in pagine.
In genere tutto ciò è del tutto trasparente al singolo processo, ma in certi
\end{prototype}
La funzione restituisce in ciascun elemento di \param{loadavg} il numero medio
-di processi attivi sulla coda dello scheduler\index{scheduler}, calcolato su
-un diverso intervalli di tempo. Il numero di intervalli che si vogliono
-leggere è specificato da \param{nelem}, dato che nel caso di Linux il carico
-viene valutato solo su tre intervalli (corrispondenti a 1, 5 e 15 minuti),
-questo è anche il massimo valore che può essere assegnato a questo argomento.
+di processi attivi sulla coda dello scheduler\index{\textit{scheduler}},
+calcolato su un diverso intervalli di tempo. Il numero di intervalli che si
+vogliono leggere è specificato da \param{nelem}, dato che nel caso di Linux il
+carico viene valutato solo su tre intervalli (corrispondenti a 1, 5 e 15
+minuti), questo è anche il massimo valore che può essere assegnato a questo
+argomento.
inizio e conclude una connessione e faremo inoltre un breve accenno al
significato di alcuni dei vari \textsl{stati} ad essa associati.
+
\subsection{La creazione della connessione: il \textit{three way handshake}}
\label{sec:TCP_conn_cre}
+\index{\textit{three~way~handshake}|(}
Il processo che porta a creare una connessione TCP è chiamato \textit{three
way handshake}; la successione tipica degli eventi (e dei
\textsl{segmenti}\footnote{Si ricordi che il segmento è l'unità elementare di
SYN consuma un byte, nel \textit{three way handshake} il numero di acknowledge
è sempre pari al numero di sequenza iniziale incrementato di uno; lo stesso
varrà anche (vedi fig.~\ref{fig:TCP_close}) per l'acknowledgement di un FIN.
+\index{\textit{three~way~handshake}|)}
+
\subsection{Le opzioni TCP.}
\label{sec:TCP_TCP_opt}
\const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è
inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_}
(riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo
-l'\textit{endianess} della macchina, ed anche se esse possono essere
-invarianti rispetto all'ordinamento dei bit, è comunque buona norma usare
-sempre la funzione \func{htonl}.
+l'\textit{endianess}\index{\textit{endianess}} della macchina, ed anche se
+esse possono essere invarianti rispetto all'ordinamento dei bit, è comunque
+buona norma usare sempre la funzione \func{htonl}.
\begin{table}[htb]
\centering
limiterà ad impostare l'indirizzo dal quale e verso il quale saranno inviati
e ricevuti i pacchetti, mentre per socket di tipo \texttt{SOCK\_STREAM} o
\texttt{SOCK\_SEQPACKET}, essa attiverà la procedura di avvio (nel caso del
- TCP il \textit{three-way-handsjake}) della connessione.} il prototipo della
-funzione è il seguente:
+ TCP il \index{\textit{three~way~handshake}}\textit{three way handshake})
+ della connessione.} il prototipo della funzione è il seguente:
\begin{prototype}{sys/socket.h}
{int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t
addrlen)}
nell'esempio sez.~\ref{sec:TCP_daytime_client}, usando le funzioni illustrate
in sez.~\ref{sec:sock_addr_func}.
-Nel caso di socket TCP la funzione \func{connect} avvia il \textit{three way
- handshake}, e ritorna solo quando la connessione è stabilita o si è
-verificato un errore. Le possibili cause di errore sono molteplici (ed i
-relativi codici riportati sopra), quelle che però dipendono dalla situazione
-della rete e non da errori o problemi nella chiamata della funzione sono le
-seguenti:
+Nel caso di socket TCP la funzione \func{connect} avvia il
+\index{\textit{three~way~handshake}}\textit{three way handshake}, e ritorna
+solo quando la connessione è stabilita o si è verificato un errore. Le
+possibili cause di errore sono molteplici (ed i relativi codici riportati
+sopra), quelle che però dipendono dalla situazione della rete e non da errori
+o problemi nella chiamata della funzione sono le seguenti:
\begin{enumerate}
\item Il client non riceve risposta al SYN: l'errore restituito è
\errcode{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla chiamata
\begin{enumerate}
\item La coda delle connessioni incomplete (\textit{incomplete connection
queue} che contiene un riferimento per ciascun socket per il quale è
- arrivato un SYN ma il \textit{three way handshake} non si è ancora concluso.
- Questi socket sono tutti nello stato \texttt{SYN\_RECV}.
+ arrivato un SYN ma il \index{\textit{three~way~handshake}}\textit{three way
+ handshake} non si è ancora concluso. Questi socket sono tutti nello stato
+ \texttt{SYN\_RECV}.
\item La coda delle connessioni complete (\textit{complete connection queue}
- che contiene un ingresso per ciascun socket per il quale il three way
- handshake è stato completato ma ancora \func{accept} non è ritornata.
+ che contiene un ingresso per ciascun socket per il quale il \textit{three
+ way handshake} è stato completato ma ancora \func{accept} non è ritornata.
Questi socket sono tutti nello stato \texttt{ESTABLISHED}.
\end{enumerate}
quando arriva un SYN da un client il server crea una nuova voce nella coda
delle connessioni incomplete, e poi risponde con il SYN$+$ACK. La voce resterà
nella coda delle connessioni incomplete fino al ricevimento dell'ACK dal
-client o fino ad un timeout. Nel caso di completamento del three way handshake
-la voce viene spostata nella coda delle connessioni complete. Quando il
-processo chiama la funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept})
-la prima voce nella coda delle connessioni complete è passata al programma, o,
-se la coda è vuota, il processo viene posto in attesa e risvegliato all'arrivo
-della prima connessione completa.
+client o fino ad un timeout. Nel caso di completamento del
+\index{\textit{three~way~handshake}}\textit{three way handshake} la voce viene
+spostata nella coda delle connessioni complete. Quando il processo chiama la
+funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept}) la prima voce
+nella coda delle connessioni complete è passata al programma, o, se la coda è
+vuota, il processo viene posto in attesa e risvegliato all'arrivo della prima
+connessione completa.
\begin{figure}[htb]
\centering
server è occupato fra chiamate successive alla \func{accept} (per cui la coda
più occupata sarebbe quella delle connessioni completate), ma piuttosto quello
di gestire la presenza di un gran numero di SYN in attesa di concludere il
-three way handshake.
+\textit{three way handshake}\index{\textit{three~way~handshake}}.
Infine va messo in evidenza che, nel caso di socket TCP, quando un SYN arriva
con tutte le code piene, il pacchetto deve essere ignorato. Questo perché la
interfaccia locale.
A questo punto si può lanciare il client, esso chiamerà \func{socket} e
-\func{connect}; una volta completato il three way handshake la connessione è
-stabilita; la \func{connect} ritornerà nel client\footnote{si noti che è
- sempre la \func{connect} del client a ritornare per prima, in quanto
- questo avviene alla ricezione del secondo segmento (l'ACK del server) del
- three way handshake, la \func{accept} del server ritorna solo dopo
- un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene
- ricevuto.} e la \func{accept} nel server, ed usando di nuovo
-\cmd{netstat} otterremmo che:
+\func{connect}; una volta completato il \textit{three way handshake} la
+connessione è stabilita; la \func{connect} ritornerà nel client\footnote{si
+ noti che è sempre la \func{connect} del client a ritornare per prima, in
+ quanto questo avviene alla ricezione del secondo segmento (l'ACK del server)
+ del \textit{three way handshake}, la \func{accept} del server ritorna solo
+ dopo un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene
+ ricevuto.} e la \func{accept} nel server, ed usando di nuovo \cmd{netstat}
+otterremmo che:
\begin{verbatim}
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
interrotta dall'arrivo di \const{SIGCHLD}, è quella ad \func{accept}, che è
l'unica funzione che può mettere il processo padre in stato di sleep nel
periodo in cui un figlio può terminare; si noti infatti come le altre
-\index{system call lente} \textit{slow system call}\footnote{si ricordi la
+\index{system~call~lente} \textit{slow system call}\footnote{si ricordi la
distinzione fatta in sez.~\ref{sec:sig_gen_beha}.} o sono chiamate prima di
entrare nel ciclo principale, quando ancora non esistono processi figli, o
sono chiamate dai figli stessi e non risentono di \const{SIGCHLD}.
Benché questo non sia un fatto comune, un evento simile può essere osservato
con dei server molto occupati. In tal caso, con una struttura del server
simile a quella del nostro esempio, in cui la gestione delle singole
-connessioni è demandata a processi figli, può accadere che il three way
-handshake venga completato e la relativa connessione abortita subito dopo,
-prima che il padre, per via del carico della macchina, abbia fatto in tempo ad
-eseguire la chiamata ad \func{accept}. Di nuovo si ha una situazione analoga
-a quella illustrata in fig.~\ref{fig:TCP_early_abort}, in cui la connessione
-viene stabilita, ma subito dopo si ha una condizione di errore che la chiude
-prima che essa sia stata accettata dal programma.
+connessioni è demandata a processi figli, può accadere che il \textit{three
+ way handshake}\index{\textit{three~way~handshake}} venga completato e la
+relativa connessione abortita subito dopo, prima che il padre, per via del
+carico della macchina, abbia fatto in tempo ad eseguire la chiamata ad
+\func{accept}. Di nuovo si ha una situazione analoga a quella illustrata in
+fig.~\ref{fig:TCP_early_abort}, in cui la connessione viene stabilita, ma
+subito dopo si ha una condizione di errore che la chiude prima che essa sia
+stata accettata dal programma.
Questo significa che, oltre alla interruzione da parte di un segnale, che
abbiamo trattato in sez.~\ref{sec:TCP_child_hand} nel caso particolare di
\end{verbatim}
Le prime tre righe vengono prodotte al momento in cui lanciamo il nostro
-client, e corrispondono ai tre pacchetti del three way handshake. L'output del
-comando riporta anche i numeri di sequenza iniziali, mentre la lettera
-\texttt{S} indica che per quel pacchetto si aveva il SYN flag attivo. Si noti
+client, e corrispondono ai tre pacchetti del
+\index{\textit{three~way~handshake}}\textit{three way handshake}. L'output
+del comando riporta anche i numeri di sequenza iniziali, mentre la lettera
+\texttt{S} indica che per quel pacchetto si aveva il SYN flag attivo. Si noti
come a partire dal secondo pacchetto sia sempre attivo il campo \texttt{ack},
seguito dal numero di sequenza per il quale si da il ricevuto; quest'ultimo, a
partire dal terzo pacchetto, viene espresso in forma relativa per maggiore
compattezza. Il campo \texttt{win} in ogni riga indica la \textit{advertising
- window} di cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può
+ window} di cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può
verificare dall'output del comando come venga appunto realizzata la sequenza
di pacchetti descritta in sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal
client un primo pacchetto con il SYN che inizia la connessione, a cui il
porta un SYN, cui il client risponde con un il terzo pacchetto di ricevuto.
Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe
-del three way handshake non avremo nulla fin tanto che non scriveremo una
-prima riga sul client; al momento in cui facciamo questo si genera una
-sequenza di altri quattro pacchetti. Il primo, dal client al server,
-contraddistinto da una lettera \texttt{P} che significa che il flag PSH è
-impostato, contiene la nostra riga (che è appunto di 11 caratteri), e ad esso
-il server risponde immediatamente con un pacchetto vuoto di ricevuto. Poi
-tocca al server riscrivere indietro quanto gli è stato inviato, per cui sarà
-lui a mandare indietro un terzo pacchetto con lo stesso contenuto appena
-ricevuto, e a sua volta riceverà dal client un ACK nel quarto pacchetto.
-Questo causerà la ricezione dell'eco nel client che lo stamperà a video.
+del \textit{three way handshake}\index{\textit{three~way~handshake}} non
+avremo nulla fin tanto che non scriveremo una prima riga sul client; al
+momento in cui facciamo questo si genera una sequenza di altri quattro
+pacchetti. Il primo, dal client al server, contraddistinto da una lettera
+\texttt{P} che significa che il flag PSH è impostato, contiene la nostra riga
+(che è appunto di 11 caratteri), e ad esso il server risponde immediatamente
+con un pacchetto vuoto di ricevuto. Poi tocca al server riscrivere indietro
+quanto gli è stato inviato, per cui sarà lui a mandare indietro un terzo
+pacchetto con lo stesso contenuto appena ricevuto, e a sua volta riceverà dal
+client un ACK nel quarto pacchetto. Questo causerà la ricezione dell'eco nel
+client che lo stamperà a video.
A questo punto noi procediamo ad interrompere l'esecuzione del server con un
\texttt{C-c} (cioè con l'invio di \const{SIGTERM}): nel momento in cui