X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileunix.tex;h=8f49c5e7b7afd24a78c647f69239c17b92557f3e;hp=7eddb1400549971a7e2d32848549f874cf73ae96;hb=c68c98c80f516ecefd08f227f54fc81fb27a7872;hpb=a29d9eebcd859ca662351848cc856e69f50c3ece diff --git a/fileunix.tex b/fileunix.tex index 7eddb14..8f49c5e 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -3,11 +3,12 @@ Esamineremo in questo capitolo la prima delle due interfacce di programmazione -per i file, quella dei \textit{file descriptor}, nativa di Unix. Questa è -l'interfaccia di basso livello provvista direttamente dalle system call, che -non prevede funzionalità evolute come la bufferizzazione o funzioni di lettura -o scrittura formattata, e sulla quale è costruita anche l'interfaccia definita -dallo standard ANSI C che affronteremo al \capref{cha:files_std_interface}. +per i file, quella dei \textit{file descriptor}\index{file descriptor}, +nativa di Unix. Questa è l'interfaccia di basso livello provvista direttamente +dalle system call, che non prevede funzionalità evolute come la +bufferizzazione o funzioni di lettura o scrittura formattata, e sulla quale è +costruita anche l'interfaccia definita dallo standard ANSI C che affronteremo +al \capref{cha:files_std_interface}. @@ -33,10 +34,10 @@ terminate le operazioni, il file dovr canale di comunicazione impedendo ogni ulteriore operazione. All'interno di ogni processo i file aperti sono identificati da un intero non -negativo, chiamato appunto \textit{file descriptor}. Quando un file viene -aperto la funzione \func{open} restituisce questo numero, tutte le ulteriori -operazioni saranno compiute specificando questo stesso valore come argomento -alle varie funzioni dell'interfaccia. +negativo, chiamato appunto \textit{file descriptor}\index{file descriptor}. +Quando un file viene aperto la funzione \func{open} restituisce questo numero, +tutte le ulteriori operazioni saranno compiute specificando questo stesso +valore come argomento alle varie funzioni dell'interfaccia. Per capire come funziona il meccanismo occorre spiegare a grandi linee come è che il kernel gestisce l'interazione fra processi e file. Il kernel mantiene @@ -56,8 +57,8 @@ particolare: \item una tabella che contiene un puntatore alla relativa voce nella \textit{file table} per ogni file aperto. \end{itemize*} -il \textit{file descriptor} in sostanza è l'intero positivo che indicizza -quest'ultima tabella. +il \textit{file descriptor}\index{file descriptor} in sostanza è l'intero +positivo che indicizza quest'ultima tabella. La \textit{file table} è una tabella che contiene una voce per ciascun file che è stato aperto nel sistema. In Linux è costituita da strutture di tipo @@ -87,23 +88,23 @@ varie strutture di dati sulla quale essa \end{figure} Ritorneremo su questo schema più volte, dato che esso è fondamentale per capire i dettagli del funzionamento dell'interfaccia dei \textit{file - descriptor}. + descriptor}\index{file descriptor}. \subsection{I file standard} \label{sec:file_std_descr} -Come accennato i \textit{file descriptor} non sono altro che un indice nella -tabella dei file aperti di ciascun processo; per questo motivo essi vengono -assegnati in successione tutte le volte che si apre un nuovo file (se non ne è -stato chiuso nessuno in precedenza). +Come accennato i \textit{file descriptor}\index{file descriptor} non sono +altro che un indice nella tabella dei file aperti di ciascun processo; per +questo motivo essi vengono assegnati in successione tutte le volte che si apre +un nuovo file (se non ne è stato chiuso nessuno in precedenza). In tutti i sistemi unix-like esiste una convenzione generale per cui ogni processo viene lanciato con almeno tre file aperti. Questi, per quanto appena -detto, avranno come \textit{file descriptor} i valori 0, 1 e 2. Benché questa -sia soltanto una convenzione, essa è seguita dalla gran parte delle -applicazioni, e non aderirvi potrebbe portare a gravi problemi di -interoperabilità. +detto, avranno come \textit{file descriptor}\index{file descriptor} i valori +0, 1 e 2. Benché questa sia soltanto una convenzione, essa è seguita dalla +gran parte delle applicazioni, e non aderirvi potrebbe portare a gravi +problemi di interoperabilità. Il primo file è sempre associato a quello che viene chiamato \textit{standard input}. È cioè il file da cui il processo si aspetta di ricevere i dati in @@ -221,7 +222,7 @@ sempre il file descriptor con il valore pi \hline % modalità di accesso al file \macro{O\_RDONLY} & apre il file in sola lettura. \\ \macro{O\_WRONLY} & apre il file in sola scrittura. \\ - \macro{O\_RDWR} & apre il file lettura/scrittura. \\ + \macro{O\_RDWR} & apre il file in lettura/scrittura. \\ \hline % modalità di apertura del file \hline \macro{O\_CREAT} & se il file non esiste verrà creato, con le regole di @@ -232,8 +233,8 @@ sempre il file descriptor con il valore pi \func{open} con \macro{EEXIST}. \\ \macro{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 (torneremo su - questo in \secref{sec:file_noblocking}). \\ + comporta che \func{open} ritorni immediatamente (l'opzione ha senso + solo per le fifo, torneremo questo in \secref{sec:ipc_named_pipe}). \\ \macro{O\_NOCTTY} & se \var{pathname} si riferisce ad un device di terminale, questo non diventerà il terminale di controllo, anche se il processo non ne ha ancora uno (si veda \secref{sec:sess_xxx}). \\ @@ -265,10 +266,11 @@ sempre il file descriptor con il valore pi file. Può causare corruzione del file con NFS se più di un processo scrive allo stesso tempo.\footnotemark\\ \macro{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per - le operazioni di I/O: 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. L'opzione è effettiva solo per - le fifo e per alcuni file di dispositivo. \\ + le operazioni di I/O (che tratteremo in \secref{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. \\ \macro{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di \macro{O\_NONBLOCK}.\\ \macro{O\_ASYNC} & apre il file per l'I/O in modalità @@ -291,13 +293,13 @@ sempre il file descriptor con il valore pi \footnotetext[2]{la man page di \func{open} segnala che questa opzione è difettosa su NFS, e che i programmi che la usano per stabilire un file di - lock possono incorrere in una race condition. Si consiglia come alternativa - di usare un file con un nome univoco e la funzione \func{link} per - verificarne l'esistenza.} + 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 l'esistenza.} -\footnotetext[3]{Denial of Service, si chiamano così attacchi miranti ad - impedire un servizio causando una qualche forma di carico eccessivo per il - sistema, che resta bloccato nelle risposte all'attacco.} +\footnotetext[3]{\textit{Denial of Service}, si chiamano così attacchi miranti + ad impedire un servizio causando una qualche forma di carico eccessivo per + il sistema, che resta bloccato nelle risposte all'attacco.} \footnotetext[4]{il problema è che NFS non supporta la scrittura in append, ed il kernel deve simularla, ma questo comporta la possibilità di una race @@ -476,8 +478,8 @@ Si tenga presente inoltre che usare \macro{SEEK\_END} non assicura affatto che successiva scrittura avvenga alla fine del file, infatti se questo è stato aperto anche da un altro processo che vi ha scritto, la fine del file può essersi spostata, ma noi scriveremo alla posizione settata in precedenza. -(questa è una potenziale sorgente di \textit{race condition}, vedi -\secref{sec:file_atomic}). +(questa è una potenziale sorgente di +\textit{race condition}\index{race condition}, vedi \secref{sec:file_atomic}). Non tutti i file supportano la capacità di eseguire una \func{lseek}, in questo caso la funzione ritorna l'errore \macro{EPIPE}. Questo, oltre che per @@ -562,16 +564,15 @@ allora ritorna immediatamente con un errore \macro{EAGAIN}\footnote{sotto BSD Linux, con le glibc, questa è sinonima di \macro{EAGAIN}.} che nel caso indica soltanto che occorrerà provare a ripetere la lettura. -La funzione \func{read} è una delle system call esistenti fin dagli abori di -Unix, ma nella seconda versione delle \textit{Single Unix +La funzione \func{read} è una delle system call fondamentali, esistenti fin +dagli albori di Unix, ma nella seconda versione delle \textit{Single Unix Specification}\footnote{questa funzione, e l'analoga \func{pwrite} sono state aggiunte nel kernel 2.1.60, il supporto nelle \acr{glibc}, compresa l'emulazione per i vecchi kernel che non hanno la system call, è stato aggiunto con la versione 2.1, in versioni precedenti sia del kernel che delle librerie la funzione non è disponibile.} (quello che viene chiamato normalmente Unix98, vedi \secref{sec:intro_opengroup}) è stata introdotta la -definizione di un'altra funzione di lettura, \func{pread}, il cui prototipo di -questa funzione è: +definizione di un'altra funzione di lettura, \func{pread}, il cui prototipo è: \begin{prototype}{unistd.h} {ssize\_t pread(int fd, void * buf, size\_t count, off\_t offset)} @@ -764,12 +765,14 @@ utilizzare meccanismi di sincronizzazione pi 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 \secref{sec:file_lseek} settare la posizione alla 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 nostro primo processo avrà ancora la posizione -corrente settata con la \func{lseek} che non corrisponde più alla fine del -file, e la successiva \func{write} sovrascriverà i dati del secondo processo. +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 settata 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à @@ -783,8 +786,8 @@ Un altro caso tipico in cui creare un 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 da parte di un altro processo che crea lo -stesso file fra il controllo e la creazione. +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. Per questo motivo sono stati introdotti pe \func{open} i due flag \macro{O\_CREAT} e \macro{O\_EXCL}. In questo modo l'operazione di controllo @@ -932,8 +935,9 @@ prototipo descriptor aperti. \end{errlist}} \end{prototype} -\noindent e qualora il file descriptor \param{newfd} sia già aperto esso -sarà chiuso e poi duplicato. +\noindent e qualora il file descriptor \param{newfd} sia già aperto (come +avviene ad esempio nel caso della duplicazione di uno dei file standard) esso +sarà prima chiuso e poi duplicato. La duplicazione dei file descriptor può essere effettuata anche usando la funzione di controllo dei file \func{fnctl} (che esamineremo in @@ -996,8 +1000,9 @@ valori di \tabref{tab:file_open_flags}). \item[\macro{F\_SETFL}] setta il \textit{file status flag} al valore specificato da \param{arg}, possono essere settati solo i bit riportati - nella terza sezione di \tabref{tab:file_open_flags}.\footnote{NdA da - verificare.} + nella terza sezione di \tabref{tab:file_open_flags}.\footnote{la man page + riporta come settabili solo \macro{O\_APPEND}, \macro{O\_NONBLOCK} e + \macro{O\_ASYNC}.} \item[\macro{F\_GETLK}] se un file lock è attivo restituisce nella struttura \param{lock} la struttura \type{flock} che impedisce l'acquisizione del blocco, altrimenti setta il campo \var{l\_type} a \macro{F\_UNLCK} (per i @@ -1033,13 +1038,17 @@ valori del segnale come \var{sa\_sigaction} usando \macro{SA\_SIGINFO}, (vedi \secref{sec:sig_sigaction}), di rendere disponibili al manipolatore informazioni ulteriori informazioni riguardo il file che ha generato il - segnale attraverso i valori restituiti in \var{siginfo\_t} (come vedremo in - \secref{sec:file_asyncronous_io}). + segnale attraverso i valori restituiti in \type{siginfo\_t} (come vedremo in + \secref{sec:file_asyncronous_io}).\footnote{i due comandi \macro{F\_SETSIG} + e \macro{F\_GETSIG} sono una estensione specifica di Linux.} \end{basedescript} La maggior parte delle funzionalità di \func{fcntl} sono troppo avanzate per poter essere affrontate in dettaglio a questo punto; saranno riprese più -avanti quando affronteremo le problematiche ad esse relative. +avanti quando affronteremo le problematiche ad esse relative (in particolare +riprenderemo le tematiche relative all'I/O asincrono in +\secref{sec:file_asyncronous_io} e quelle relative al \textit{file locking} in +\secref{sec:file_locking}). Per determinare le modalità di accesso inoltre è necessario estrarre i bit di accesso (ottenuti con il comando \macro{F\_GETFL}); infatti la definizione