ulteriori operazioni dovranno essere compiute specificando questo stesso
numero come argomento alle varie funzioni dell'interfaccia.
+\itindbeg{process~table}
+\itindbeg{file~table}
+
Per capire come funziona il meccanismo occorre spiegare a grandi linee come il
kernel gestisce l'interazione fra processi e file. Abbiamo già accennato in
sez.~\ref{sec:proc_hierarchy} come il kernel mantenga un elenco di tutti
-processi nella cosiddetta \itindex{process~table} \textit{process table}. Lo
-stesso, come accennato in sez.~\ref{sec:file_vfs_work}, vale anche per tutti i
-file aperti, il cui elenco viene mantenuto nella cosiddetta
-\itindex{file~table} \textit{file table}.
-
-La \itindex{process~table} \textit{process table} è una tabella che contiene
-una voce per ciascun processo attivo nel sistema. Ciascuna voce è costituita
-dal puntatore a una struttura di tipo \kstruct{task\_struct} nella quale sono
-raccolte tutte le informazioni relative al processo, fra queste informazioni
-c'è anche il puntatore ad una ulteriore struttura di tipo
+processi nella cosiddetta \textit{process table}. Lo stesso, come accennato in
+sez.~\ref{sec:file_vfs_work}, vale anche per tutti i file aperti, il cui
+elenco viene mantenuto nella cosiddetta \textit{file table}.
+
+La \textit{process table} è una tabella che contiene una voce per ciascun
+processo attivo nel sistema. Ciascuna voce è costituita dal puntatore a una
+struttura di tipo \kstruct{task\_struct} nella quale sono raccolte tutte le
+informazioni relative al processo, fra queste informazioni c'è anche il
+puntatore ad una ulteriore struttura di tipo
\kstruct{files\_struct},\footnote{la definizione corrente di questa struttura
si trova nel file \texttt{include/linux/fdtable.h} dei sorgenti del kernel,
quella mostrata in fig.~\ref{fig:file_proc_file} è una versione pesantemente
semplificata.} che contiene le informazioni relative ai file che il processo
ha aperto.
-La \itindex{file~table} \textit{file table} è una tabella che contiene una
-voce per ciascun file che è stato aperto nel sistema. Come accennato in
-sez.~\ref{sec:file_vfs_work} per ogni file aperto viene allocata una struttura
-\kstruct{file} e la \textit{file table} è costituita da un elenco di puntatori
-a ciascuna di queste strutture, che, come illustrato in
-fig.~\ref{fig:kstruct_file}, contengono le informazioni necessarie per la
-gestione dei file, ed in particolare:
+La \textit{file table} è una tabella che contiene una voce per ciascun file
+che è stato aperto nel sistema. Come accennato in sez.~\ref{sec:file_vfs_work}
+per ogni file aperto viene allocata una struttura \kstruct{file} e la
+\textit{file table} è costituita da un elenco di puntatori a ciascuna di
+queste strutture, che, come illustrato in fig.~\ref{fig:kstruct_file},
+contengono le informazioni necessarie per la gestione dei file, ed in
+particolare:
\begin{itemize*}
\item i flag di stato \itindex{file~status~flag} del file nel campo
\var{f\_flags}.
In fig.~\ref{fig:file_proc_file} si è riportato uno schema semplificato in cui
è illustrata questa architettura, ed in cui si sono evidenziate le
-interrelazioni fra la \itindex{file~table} \textit{file table}, la
-\itindex{process~table} \textit{process table} e le varie strutture di dati
-che il kernel mantiene per ciascun file e ciascun processo.
+interrelazioni fra la \textit{file table}, la \textit{process table} e le
+varie strutture di dati che il kernel mantiene per ciascun file e ciascun
+processo.
Come si può notare alla fine il collegamento che consente di porre in
relazione i file ed i processi è effettuato attraverso i dati mantenuti nella
In questa infrastruttura un \textit{file descriptor} non è altro che l'intero
positivo che indicizza quest'ultima tabella, e che consente di recuperare il
puntatore alla struttura \kstruct{file} corrispondente al file aperto dal
-processo a cui era stato assegnato questo indice. Una volta ottenuta grazie
-al \textit{file descriptor} la struttura \kstruct{file} corrispondente al file
-voluto nella \itindex{file~table} \textit{file table}, il kernel potrà usare
-le funzioni messe disposizione dal VFS per eseguire sul file tutte le
-operazioni necessarie.
+processo a cui era stato assegnato questo indice. Una volta ottenuta grazie al
+\textit{file descriptor} la struttura \kstruct{file} corrispondente al file
+voluto nella \textit{file table}, il kernel potrà usare le funzioni messe
+disposizione dal VFS per eseguire sul file tutte le operazioni necessarie.
+
+\itindend{process~table}
+\itindend{file~table}
+
Il meccanismo dell'apertura dei file prevede che venga sempre fornito il primo
\textit{file descriptor} libero nella tabella, e per questo motivo essi
supportata su NFS solo a partire da NFSv3 e con il kernel 2.6, nelle versioni
precedenti la funzionalità viene emulata controllando prima l'esistenza del
file per cui usarla per creare \index{file!di lock} un file di lock potrebbe
-dar luogo a una \itindex{race~condition} \textit{race condition}.\footnote{un
- file potrebbe venir creato fra il controllo la successiva apertura con
- \const{O\_CREAT}, la cosa si può risolvere comunque creando un file con un
- nome univoco ed usando la funzione \func{link} per creare il \index{file!di
- lock} file di lock, (vedi sez.~\ref{sec:ipc_file_lock}).}
+dar luogo a una \textit{race condition}.\footnote{un file potrebbe venir
+ creato fra il controllo la successiva apertura con \const{O\_CREAT}, la cosa
+ si può risolvere comunque creando un file con un nome univoco ed usando la
+ funzione \func{link} per creare il \index{file!di lock} file di lock, (vedi
+ sez.~\ref{sec:ipc_file_lock}).}
Se si usa \const{O\_EXCL} senza \const{O\_CREAT} il comportamento è
indefinito. Nella creazione di un file con \const{O\_CREAT} occorre sempre
viene sempre aggiunto al contenuto precedente. Con
NFS questa funzionalità non è supportata
e viene emulata, per questo possono verificarsi
- \itindex{race~condition} \textit{race
- condition} con una sovrapposizione dei dati se
- più di un processo scrive allo stesso tempo.\\
+ \textit{race condition} con una sovrapposizione dei
+ dati se più di un processo scrive allo stesso
+ tempo.\\
\const{O\_ASYNC} & Apre il file per l'I/O in modalità asincrona (vedi
sez.~\ref{sec:signal_driven_io}). Quando è
impostato viene generato il segnale \signal{SIGIO}
sez.~\ref{sec:proc_exec}) sul file. Il flag è
previsto dallo standard POSIX.1-2008, ed è stato
introdotto con il kernel 2.6.23 per evitare una
- \itindex{race~condition} \textit{race condition}
- che si potrebbe verificare con i \textit{thread}
- fra l'apertura del file e l'impostazione della
- suddetta modalità con \func{fcntl} (vedi
- sez.~\ref{sec:file_fcntl_ioctl}).\\
+ \textit{race condition} che si potrebbe verificare
+ con i \textit{thread} fra l'apertura del file e
+ l'impostazione della suddetta modalità con
+ \func{fcntl} (vedi
+ sez.~\ref{sec:file_fcntl_ioctl}).\\
\const{O\_DIRECT} & Esegue l'I/O direttamente dalla memoria in
\textit{user space} in maniera sincrona, in modo da
scavalcare i meccanismi di bufferizzazione del
Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui
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 \itindex{race~condition}
-\textit{race condition}l 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 primo processo, che avrà la
-posizione corrente che aveva impostato con la \func{lseek} che non corrisponde
-più alla fine del file, e la sua successiva \func{write} sovrascriverà i dati
-del secondo processo.
+fine del file e poi scrivere può condurre ad una \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 primo processo, avrà una posizione corrente che aveva
+impostato con la \func{lseek} che non corrisponde più alla fine del file, e la
+sua successiva \func{write} sovrascriverà i dati del secondo processo.
Il problema deriva dal fatto che usare due \textit{system call} in successione
non è mai un'operazione atomica dato che il kernel può interrompere
\begin{errlist}
\item[\errcode{EBADF}] \param{oldfd} non è un file aperto o \param{newfd} ha
un valore fuori dall'intervallo consentito per i file descriptor.
- \item[\errcode{EBUSY}] si è rilevata la possibilità di una
- \itindex{race~condition} \textit{race condition}.
+ \item[\errcode{EBUSY}] si è rilevata la possibilità di una \textit{race
+ condition}.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\item[\errcode{EMFILE}] si è raggiunto il numero massimo consentito di file
descriptor aperti.
L'uso di \func{dup2} ha vari vantaggi rispetto alla combinazione di
\func{close} e \func{dup}; anzitutto se \param{oldfd} è uguale \param{newfd}
questo verrebbe chiuso e \func{dup} fallirebbe, ma soprattutto l'operazione è
-atomica e consente di evitare una \itindex{race~condition} \textit{race
- condition} in cui dopo la chiusura del file si potrebbe avere la ricezione
-di un segnale il cui gestore (vedi sez.~\ref{sec:sig_signal_handler}) potrebbe
-a sua volta aprire un file, per cui alla fine \func{dup} restituirebbe un file
-descriptor diverso da quello voluto.
+atomica e consente di evitare una \textit{race condition} in cui dopo la
+chiusura del file si potrebbe avere la ricezione di un segnale il cui gestore
+(vedi sez.~\ref{sec:sig_signal_handler}) potrebbe a sua volta aprire un file,
+per cui alla fine \func{dup} restituirebbe un file descriptor diverso da
+quello voluto.
Con Linux inoltre la funzione prevede la possibilità di restituire l'errore
\errcode{EBUSY}, che non è previsto dallo standard, quando viene rilevata la
-possibilità di una \itindex{race~condition} \textit{race condition} interna in
-cui si cerca di duplicare un file descriptor che è stato allocato ma per il
-quale non sono state completate le operazioni di apertura.\footnote{la
- condizione è abbastanza peculiare e non attinente al tipo di utilizzo
- indicato, quanto piuttosto ad un eventuale tentativo di duplicare file
- descriptor non ancora aperti, la condizione di errore non è prevista dallo
- standard, ma in condizioni simili FreeBSD risponde con un errore di
- \errval{EBADF}, mentre OpenBSD elimina la possibilità di una \textit{race
- condition} al costo di una perdita di prestazioni.} In tal caso occorre
-ritentare l'operazione.
+possibilità di una \textit{race condition} interna in cui si cerca di
+duplicare un file descriptor che è stato allocato ma per il quale non sono
+state completate le operazioni di apertura.\footnote{la condizione è
+ abbastanza peculiare e non attinente al tipo di utilizzo indicato, quanto
+ piuttosto ad un eventuale tentativo di duplicare file descriptor non ancora
+ aperti, la condizione di errore non è prevista dallo standard, ma in
+ condizioni simili FreeBSD risponde con un errore di \errval{EBADF}, mentre
+ OpenBSD elimina la possibilità di una \textit{race condition} al costo di
+ una perdita di prestazioni.} In tal caso occorre ritentare l'operazione.
La duplicazione dei file descriptor può essere effettuata anche usando la
funzione di controllo dei file \func{fcntl} (che esamineremo in
quando un \textit{pathname} relativo non fa riferimento ad un file posto
direttamente nella directory di lavoro corrente, che alcuni dei componenti del
\textit{pathname} vengano modificati in parallelo alla chiamata a \func{open},
-cosa che lascia aperta la possibilità di una \itindex{race~condition}
-\textit{race condition} in cui c'è spazio per un \itindex{symlink~attack}
-\textit{symlink attack} (si ricordi quanto visto per \func{access} in
-sez.~\ref{sec:file_perm_management}).
+cosa che lascia aperta la possibilità di una \textit{race condition} in cui
+c'è spazio per un \itindex{symlink~attack} \textit{symlink attack} (si ricordi
+quanto visto per \func{access} in sez.~\ref{sec:file_perm_management}).
Inoltre come già accennato, la directory di lavoro corrente è una proprietà
del singolo processo; questo significa che quando si lavora con i
quando si lavora con i \itindex{thread} \textit{thread}, si può mantenere una
directory di lavoro diversa per ciascuno di essi.
-Questo metodo, oltre a risolvere i problemi di \itindex{race~condition}
-\textit{race condition}, consente anche di ottenere aumenti di prestazioni
-significativi quando si devono eseguire molte operazioni su sezioni
-dell'albero dei file che prevedono delle gerarchie di sottodirectory molto
-profonde. Infatti in questo caso basta eseguire la risoluzione del
-\textit{pathname} della directory di partenza una sola volta (nell'apertura
-iniziale) e non tutte le volte che si deve accedere a ciascun file che essa
-contiene.
+Questo metodo, oltre a risolvere i problemi di \textit{race condition},
+consente anche di ottenere aumenti di prestazioni significativi quando si
+devono eseguire molte operazioni su sezioni dell'albero dei file che prevedono
+delle gerarchie di sottodirectory molto profonde. Infatti in questo caso basta
+eseguire la risoluzione del \textit{pathname} della directory di partenza una
+sola volta (nell'apertura iniziale) e non tutte le volte che si deve accedere
+a ciascun file che essa contiene.
La sintassi generale di queste nuove funzioni è che esse prevedono come primo
argomento il file descriptor della directory da usare come base per la
La funzione \func{getc} legge un byte da \param{stream} e lo restituisce come
intero, ed in genere è implementata come una macro per cui può avere
-\itindex{side~effects} \textit{side effects}, mentre \func{fgetc} è assicurato
-essere sempre una funzione. Infine \func{getchar} è equivalente a
-\code{getc(stdin)}.
+\textit{side effects}, mentre \func{fgetc} è assicurato essere sempre una
+funzione. Infine \func{getchar} è equivalente a \code{getc(stdin)}.
A parte \func{getchar}, che si usa in genere per leggere un carattere da
tastiera, le altre due funzioni sono sostanzialmente equivalenti. La