X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=b376483c6c301882c1bb1698522287ff365fa29e;hp=9d084a86285ba36c4018a419088209987e2172cd;hb=76ddae490a29dac41729cfae51f76e5c9987a484;hpb=132101028053d47151d1957b925fc5a7631c01e6 diff --git a/fileadv.tex b/fileadv.tex index 9d084a8..b376483 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1,34 +1,230 @@ -\chapter{I/O avanzato} +\chapter{La gestione avanzata dei file} \label{cha:file_advanced} +In questo capitolo affronteremo le tematiche relative alla gestione avanzata +dei file, che non sono state trattate in \capref{cha:file_unix_interface}, +dove ci si è limitati ad una panoramica delle funzioni base. In particolare +tratteremo delle funzioni di input/output avanzato e del \textit{file + locking}. +\section{Le funzioni di I/O avanzato} +\label{sec:file_advanced_io} -\section{I/O non bloccante} +In questa sezione esamineremo le funzioni che permettono una gestione più +sofisticata dell'I/O su file, a partire da quelle che permettono di gestire +l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O +mappato in memoria. + + +\subsection{La modalità di I/O \textsl{non-bloccante}} \label{sec:file_noblocking} +Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra +\textit{fast} e \textit{slow} system call, 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 ed alcuni 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 è quello che si verifica quando si +devono eseguire operazioni che possono bloccarsi su più file descriptor: +mentre si è bloccati su uno di questi file su di un'altro potrebbero essere +presenti dei dati, così che nel migliore dei casi si avrebbe una lettura +ritardata inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un +deadlock. + +Abbiamo già accennato in \secref{sec:file_open} che però è possibile prevenire +questo tipo di comportamento aprendo un file in modalità +\textsl{non-bloccante}, attraverso l'uso del flag \macro{O\_NONBLOCK} nella +chiamata di \func{open}. In questo caso le funzioni di input/output che +altrimenti si sarebbero bloccate ritornano immediatamente, restituendo +l'errore \macro{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}, è estremamente inefficiente: si tiene costantemente +impiegata la CPU solo per eseguire in continuazione delle system call che +nella gran parte dei casi falliranno. Per evitare questo, come vedremo in +\secref{sec:file_multiplexing}, è stata introdotta una nuova interfaccia di +programmazione, che comporta comunque l'uso della modalità di I/O non +bloccante. + +\subsection{Le funzioni \func{poll} e \func{select}} +\label{sec:file_multiplexing} + +Per superare il problema di dover usare il \textit{polling} controllare la +disponibilità di accesso ad un file aperto in modalità non bloccante, sia BSD +che System V hanno introdotto delle nuove funzioni in grado di sospendere +l'esecuzione di un processo fino a che l'accesso diventi possibile; il primo +ad introdurre questa nuova interfaccia, chiamata usualmente \textit{I/O + multiplexing}, è stato BSD, con l'introduzione della funzione \func{select}, +il cui prototipo è: +\begin{prototype}{sys/select.h} + {int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds, + struct timeval *timeout)} + +Attende che un certo insieme di file descriptor cambi stato. + +\bodydesc{La funzione restituisce il numero di file descriptor, anche nullo, + che hanno cambiato stato in caso di successo e -1 in caso di errore, nel + qual caso \var{errno} viene settata ai valori: + \begin{errlist} + \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno + degli insiemi. + \item[\macro{EINTR}] La funzione è stata interrotta da un segnale. + \item[\macro{EINVAL}] Si è specificato per \param{n} un valore negativo. + \end{errlist} + ed inoltre \macro{ENOMEM}. +} +\end{prototype} + +La funzione mette il processo in stato di \textit{sleep} (vedi +\tabref{tab:proc_proc_states}) fintanto che non viene rilevate dell'attività +sull'insieme dei file descriptor specificati (\param{readfds}, +\param{writefds} e \param{exceptfds}), per un tempo massimo specificato da +\param{timeout}. + +Per specificare quali file descriptor si intende 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 \textit{signal set} (vedi \secref{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: +\begin{functions} + \headdecl{sys/select.h} + \funcdecl{FD\_ZERO(fd\_set *set)} + Inizializza l'insieme (vuoto). + + \funcdecl{FD\_SET(int fd, fd\_set *set)} + Inserisce il file descriptor \param{fd} nell'insieme. + + \funcdecl{FD\_CLR(int fd, fd\_set *set)} + Rimuove il file descriptor \param{fd} nell'insieme. + + \funcdecl{FD\_ISSET(int fd, fd\_set *set)} + Controlla se il file descriptor \param{fd} è nell'insieme. +\end{functions} + +In genere un \textit{file descriptor set} può contenere fino ad un massimo di +\macro{FD\_SETSIZE} file descriptor. Questo a seconda del sistema può essere +il limite del numero massimo di file aperti\footnote{ad esempio in Linux, fino + alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma quando, +come nelle versioni più recenti del kernel, questo limite non c'è un massimo, +esso indica le dimensioni in numero di bit utilizzabili per l'insieme. + +La funzione richiede di specificare tre insiemi distinti di file descriptor; +il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di +input in lettura, il secondo, \param{writefds} per verificare la possibilità +di scrivere ed il terzo, \param{exceptfds}, per verificare l'esistenza di +eccezioni. I corrispondenti valori dei \textit{file descriptor set} saranno +modificati di conseguenza per mostrare quale dei file descriptor ha cambiato +stato. + + + + + +Come accennato l'interfaccia di \func{select} è una estensione aggiunta BSD, e +poi entrata a far parte di POSIX; allo stesso tempo System V aveva introdotto +una interfaccia alternativa, basata sulla funzione \func{poll}, il cui +prototipo è: +\begin{prototype}{sys/poll.h} + {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)} + +La funzione attente un cambiamento di stato per uno dei file descriptor +specificati da \param{ufds}. + +\bodydesc{La funzione restituisce il numero di file descriptor con attività in + caso di successo, o 0 se c'è stato un timeout; in caso di errore viene + restituito -1 ed \var{errno} viene settata ai valori: + +.} +\end{prototype} + + + + +\subsection{L'I/O asincrono} +\label{sec:file_asyncronous_io} + +Una modalità alternativa all'uso dell'I/O non bloccante è quella di fare +ricorso all'I/O asincrono. Abbiamo accennato in \secref{sec:file_open} che è +possibile, attraverso l'uso del flag \macro{O\_ASYNC}, aprire un file in +modalità asincrona, così come è possibile settare questo flag attraverso l'uso +di \func{fcntl}. + +In tal caso il sistema genera un segnale \macro{SIGIO} tutte le volte che sono +presenti dei dati in input su un file aperto in questa modalità. Uno dei +problemi che si presentavano con le prime implementazioni di questa modalità +di I/O è che essa poteva essere usata in maniera semplice aprendo un solo file +per processo, dato che altrimenti si sarebbe dovuto provvedere ad effettuare +una serie di controlli su tutti i file aperti per distinguere a quale fosse +dovuto l'emissione del segnale. + +Tutto questo adesso può essere evitato facendo ricorso alle informazioni +restituite al manipolatore del segnale attraverso la struttura +\var{siginfo\_t} (vedi \figref{fig:sig_siginfo_t}), il cui campo \var{si\_fd} +riporta il file descriptor che ha generato il segnale. + + + +\subsection{File mappati in memoria} +\label{sec:file_memory_map} -\section{File locking} +\subsection{I/O multiplo} +\label{sec:file_multiple_io} + + + +\section{Il file locking} \label{sec:file_locking} +In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un +sistema unix-like gestisce la condivisione dei file da parte di processi +diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti +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. -\section{I/O multiplexato} -\label{sec:file_multiplexing} +In tutti questi casi il \textit{file locking} è la tecnica che permette di +evitare le 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. -%\section{I/O asincrono} -%\label{sec:file_asynchronous} +\subsection{L'\textit{advisory locking}} +\label{sec:file_record_locking} + +La prima modalità di file locking che è stata implementata nei sistemi +unix-like è quella che viene usualmente chiamata \textit{advisory locking}, in +quanto è il processo, e non il sistema, che si incarica di verificare se +esiste una condizione di blocco per l'accesso ai file. + + + + +\subsection{Il \textit{mandatory locking}} +\label{sec:file_mand_locking} + +Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4, + -%Non supportato in Linux, in BSD e SRv4 c'è, ma usando il segnale \macro{SIGIO} -%per indicare che i dati sono disponibili, può essere usato in maniera semplice -%con un solo file per processo (altrimenti non sarebbe più possibile -%distinguere da quale file proviene l'attività che ha causato l'emissione del -%segnale). -\section{File mappati in memoria} -\label{sec:file_memory_map} +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: