X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=4415602bcce799513de037ee02f7867f09dfc093;hp=5203d17744dea60987154e798317d27c9a4391af;hb=c48d3a056c974898ca18c27a918f2296c18e2c6e;hpb=758b135b7f04cdcebc4fe2726dc540cb24d116ba diff --git a/fileadv.tex b/fileadv.tex index 5203d17..4415602 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1,6 +1,6 @@ %% fileadv.tex %% -%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2003 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Prefazione", @@ -70,15 +70,15 @@ I/O non bloccante. \label{sec:file_multiplexing} Per superare il problema di dover usare il \textit{polling}\index{polling} per -controllare la possibilità di effettuare operazioni su 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 in attesa che -l'accesso diventi possibile. Il primo ad introdurre questa modalità di -operazione, chiamata usualmente \textit{I/O multiplexing}, è stato -BSD,\footnote{la funzione è apparsa in BSD4.2 e standardizzata in BSD4.4, ma è - stata portata su tutti i sistemi che supportano i - \textit{socket}\index{socket}, compreso le varianti di System V.} con la -funzione \funcd{select}, il cui prototipo è: +controllare la possibilità di effettuare operazioni su un gruppo di file +aperti in modalità non bloccante, sia BSD che System V hanno introdotto delle +nuove funzioni in grado di sospendere l'esecuzione di un processo fin quando +l'accesso ad un dato insieme di file diventi possibile. Il primo ad +introdurre questa modalità di operazione, chiamata usualmente \textit{I/O + multiplexing}, è stato BSD,\footnote{la funzione è apparsa in BSD4.2 e + standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che + supportano i \textit{socket}\index{socket}, compreso le varianti di System + V.} con la funzione \funcd{select}, il cui prototipo è: \begin{functions} \headdecl{sys/time.h} \headdecl{sys/types.h} @@ -135,10 +135,14 @@ opportune macro di preprocessore: In genere un \textit{file descriptor set} può contenere fino ad un massimo di \const{FD\_SETSIZE} file descriptor. Questo valore in origine corrispondeva al limite per il 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 + fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma da quando, come nelle versioni più recenti del kernel, non c'è più un limite massimo, esso indica le dimensioni massime dei numeri usati nei \textit{file - descriptor set}. + descriptor set}.\footnote{il suo valore, secondo lo standard POSIX + 1003.1-2001, è definito in \file{sys/select.h}, ed è pari a 1024.} Si tenga +presente che i \textit{file descriptor set} devono sempre essere inizializzati +con \macro{FD\_ZERO}; passare a \func{select} un valore non inizializzato può +dar luogo a comportamenti non prevedibili. La funzione richiede di specificare tre insiemi distinti di file descriptor; il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di @@ -147,17 +151,24 @@ possibilit verificare l'esistenza di condizioni eccezionali (come i messaggi urgenti su un \textit{socket}\index{socket}, vedi \secref{sec:xxx_urgent}). -La funzione inoltre richiede anche di specificare, tramite l'argomento -\param{n}, un valore massimo del numero dei file descriptor usati -nell'insieme; si può usare il già citato \const{FD\_SETSIZE}, oppure il numero -più alto dei file descriptor usati nei tre insiemi, aumentato di uno. +Dato che in genere non si tengono mai sotto controllo fino a +\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di +specificare qual'è il numero massimo dei file descriptor indicati nei tre +insiemi precedenti. Questo viene fatto per efficienza, per evitare di passare +e far controllare al kernel una quantità di memoria superiore a quella +necessaria. Questo limite viene indicato tramite l'argomento \param{n}, che +deve corrispondere al valore massimo aumentato di uno.\footnote{i file + descriptor infatti sono contati a partire da zero, ed il valore indica il + numero di quelli da tenere sotto controllo; dimenticarsi di aumentare di uno + il valore di \param{n} è un errore comune.} Infine l'argomento \param{timeout}, specifica un tempo massimo di -attesa\footnote{il tempo è valutato come \textit{elapsed time}.} prima che la -funzione ritorni; se impostato a \val{NULL} la funzione attende -indefinitamente. Si può 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. +attesa\footnote{il tempo è valutato come \textit{clock time} (vedi + \secref{sec:sys_unix_time}).} prima che la funzione ritorni; se impostato a +\val{NULL} la funzione attende indefinitamente. Si può 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. La funzione restituisce il totale dei file descriptor pronti nei tre insiemi, il valore zero indica sempre che si è raggiunto un timeout. Ciascuno dei tre @@ -167,35 +178,35 @@ operazioni ad esso relative, in modo da poterlo controllare con la macro non vengono toccati. In Linux \func{select} modifica anche il valore di \param{timeout}, -impostandolo al tempo restante; questo è utile quando la funzione viene -interrotta da un segnale, in tal caso infatti si ha un errore di -\errcode{EINTR}, ed occorre rilanciare la funzione; in questo modo non è -necessario ricalcolare tutte le volte il tempo rimanente.\footnote{questo può - causare problemi di portabilità sia quando si trasporta codice scritto su - Linux che legge questo valore, sia quando si usano programmi scritti per - altri sistemi che non dispongono di questa caratteristica e ricalcolano - \param{timeout} tutte le volte. In genere la caratteristica è disponibile - nei sistemi che derivano da System V e non disponibile per quelli che - derivano da BSD.} - -Come accennato l'interfaccia di \func{select} è una estensione di BSD; anche -System V ha introdotto una sua interfaccia per gestire l'\textit{I/O - multiplexing}, basata sulla funzione \funcd{poll},\footnote{la funzione è - prevista dallo standard XPG4, ed è stata introdotta in Linux come system - call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} il cui +impostandolo al tempo restante in caso di interruzione prematura; questo è +utile quando la funzione viene interrotta da un segnale, in tal caso infatti +si ha un errore di \errcode{EINTR}, ed occorre rilanciare la funzione; in +questo modo non è necessario ricalcolare tutte le volte il tempo +rimanente.\footnote{questo può causare problemi di portabilità sia quando si + trasporta codice scritto su Linux che legge questo valore, sia quando si + usano programmi scritti per altri sistemi che non dispongono di questa + caratteristica e ricalcolano \param{timeout} tutte le volte. In genere la + caratteristica è disponibile nei sistemi che derivano da System V e non + disponibile per quelli che derivano da BSD.} + +Come accennato l'interfaccia di \func{select} è una estensione creata nello +sviluppo di BSD; anche System V ha introdotto una sua interfaccia per gestire +l'\textit{I/O multiplexing}, basata sulla funzione \funcd{poll},\footnote{la + funzione è prevista dallo standard XPG4, ed è stata introdotta in Linux come + system call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} 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}. + + La funzione attende 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} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno - degli insiemi. + degli insiemi. \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. \end{errlist} ed inoltre \errval{EFAULT} e \errval{ENOMEM}.} @@ -211,17 +222,11 @@ negativo indica un'attesa indefinita). \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ -}; - \end{lstlisting} + \includestruct{listati/pollfd.h} \end{minipage} \normalsize - \caption{La struttura \struct{pollfd}, utilizzata per specificare le modalità - di controllo di un file descriptor alla funzione \func{poll}.} + \caption{La struttura \structd{pollfd}, utilizzata per specificare le + modalità di controllo di un file descriptor alla funzione \func{poll}.} \label{fig:file_pollfd} \end{figure} @@ -254,7 +259,8 @@ vengono utilizzati solo per \var{revents} come valori in uscita). \const{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali. \\ \const{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad alta priorità. \\ - \const{POLLMSG} & 0x400 & Estensione propria di Linux.\\ + \const{POLLMSG} & 0x400 & Un segnale \const{SIGPOLL} è arrivato alla + cima dello stream.\\ \hline \end{tabular} \caption{Costanti per l'identificazione dei vari bit dei campi @@ -321,6 +327,15 @@ segnale che non sarebbe rilevato; la race condition\index{race condition} diventa superabile disabilitando il segnale prima del test e riabilitandolo poi grazie all'uso di \param{sigmask}. +Dato che l'I/O multiplexing serve a risolvere il problema di dover attendere +la disponibilità di accesso ad un insieme di file, esso viene utilizzato +prevalentemente per programmi in cui l'accesso ad un file descriptor può +essere bloccante. Abbiamo già accennato come questo non avvenga mai per i +normali file su disco; l'uso più comune di queste funzioni infatti è nei +server di rete, in cui esse vengono utilizzate per tenere sotto controllo vari +socket; pertanto ritorneremo su di esse con maggiori dettagli e con qualche +esempio in \secref{sec:TCP_sock_multiplexing}. + \subsection{L'I/O asincrono} @@ -421,21 +436,10 @@ disponibilit \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct aiocb -{ - int aio_fildes; /* File descriptor. */ - off_t aio_offset; /* File offset */ - int aio_lio_opcode; /* Operation to be performed. */ - int aio_reqprio; /* Request priority offset. */ - volatile void *aio_buf; /* Location of buffer. */ - size_t aio_nbytes; /* Length of transfer. */ - struct sigevent aio_sigevent; /* Signal number and value. */ -}; - \end{lstlisting} + \includestruct{listati/aiocb.h} \end{minipage} \normalsize - \caption{La struttura \struct{aiocb}, usata per il controllo dell'I/O + \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O asincrono.} \label{fig:file_aiocb} \end{figure} @@ -471,20 +475,11 @@ esse. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct sigevent -{ - sigval_t sigev_value; - int sigev_signo; - int sigev_notify; - void (*sigev_notify_function)(sigval_t); - pthread_attr_t *sigev_notify_attributes; -}; - \end{lstlisting} + \includestruct{listati/sigevent.h} \end{minipage} \normalsize - \caption{La struttura \struct{sigevent}, usata per specificare le modalità di - notifica degli eventi relativi alle operazioni di I/O asincrono.} + \caption{La struttura \structd{sigevent}, usata per specificare le modalità + di notifica degli eventi relativi alle operazioni di I/O asincrono.} \label{fig:file_sigevent} \end{figure} @@ -818,15 +813,10 @@ il secondo, \var{iov\_len}, la dimensione dello stesso. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct iovec { - __ptr_t iov_base; /* Starting address */ - size_t iov_len; /* Length in bytes */ -}; - \end{lstlisting} + \includestruct{listati/iovec.h} \end{minipage} \normalsize - \caption{La struttura \struct{iovec}, usata dalle operazioni di I/O + \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O vettorizzato.} \label{fig:file_iovec} \end{figure} @@ -1512,18 +1502,10 @@ regione bloccata. \begin{figure}[!bht] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct flock { - short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ - short int l_whence; /* Where `l_start' is relative to (like `lseek'). */ - off_t l_start; /* Offset where the lock begins. */ - off_t l_len; /* Size of the locked area; zero means until EOF. */ - pid_t l_pid; /* Process holding the lock. */ -}; - \end{lstlisting} + \includestruct{listati/flock.h} \end{minipage} \normalsize - \caption{La struttura \struct{flock}, usata da \func{fcntl} per il file + \caption{La struttura \structd{flock}, usata da \func{fcntl} per il file locking.} \label{fig:struct_flock} \end{figure} @@ -1717,60 +1699,7 @@ necessario a soddisfare l'operazione richiesta. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int main(int argc, char *argv[]) -{ - int type = F_UNLCK; /* lock type: default to unlock (invalid) */ - off_t start = 0; /* start of the locked region: default to 0 */ - off_t len = 0; /* length of the locked region: default to 0 */ - int fd, res, i; /* internal variables */ - int bsd = 0; /* semantic type: default to POSIX */ - int cmd = F_SETLK; /* lock command: default to non-blocking */ - struct flock lock; /* file lock structure */ - ... - if ((argc - optind) != 1) { /* There must be remaing parameters */ - printf("Wrong number of arguments %d\n", argc - optind); - usage(); - } - if (type == F_UNLCK) { /* There must be a -w or -r option set */ - printf("You should set a read or a write lock\n"); - usage(); - } - fd = open(argv[optind], O_RDWR); /* open the file to be locked */ - if (fd < 0) { /* on error exit */ - perror("Wrong filename"); - exit(1); - } - /* do lock */ - if (bsd) { /* if BSD locking */ - /* rewrite cmd for suitables flock operation values */ - if (cmd == F_SETLKW) { /* if no-blocking */ - cmd = LOCK_NB; /* set the value for flock operation */ - } else { /* else */ - cmd = 0; /* default is null */ - } - if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */ - if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */ - res = flock(fd, cmd); /* esecute lock */ - } else { /* if POSIX locking */ - /* setting flock structure */ - lock.l_type = type; /* set type: read or write */ - lock.l_whence = SEEK_SET; /* start from the beginning of the file */ - lock.l_start = start; /* set the start of the locked region */ - lock.l_len = len; /* set the length of the locked region */ - res = fcntl(fd, cmd, &lock); /* do lock */ - } - /* check lock results */ - if (res) { /* on error exit */ - perror("Failed lock"); - exit(1); - } else { /* else write message */ - printf("Lock acquired\n"); - } - pause(); /* stop the process, use a signal to exit */ - return 0; -} - \end{lstlisting} + \includecodesample{listati/Flock.c} \end{minipage} \normalsize \caption{Sezione principale del codice del programma \file{Flock.c}.}