%% 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",
\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}
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
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
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}.}
\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}
\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
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}
\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}
\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}
\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}
\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}
\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}.}