From: Simone Piccardi Date: Mon, 15 Jul 2002 17:14:31 +0000 (+0000) Subject: Fatta prima parte dell'I/O asincrono (quella relativa a SIGIO) X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=c68c98c80f516ecefd08f227f54fc81fb27a7872;p=gapil.git Fatta prima parte dell'I/O asincrono (quella relativa a SIGIO) iniziata la parte relativa a POSIX.1b --- diff --git a/fileadv.tex b/fileadv.tex index 7b3a6b1..591f149 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -55,7 +55,7 @@ bloccante. -\subsection{Le funzioni \func{poll} e \func{select}} +\subsection{L'I/O multiplexing} \label{sec:file_multiplexing} Per superare il problema di dover usare il \textit{polling} per controllare la @@ -67,9 +67,12 @@ usualmente \textit{I/O multiplexing}, apparsa in BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che supportano i \textit{socket}, compreso le varianti di System V.} con la 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)} +\begin{functions} + \headdecl{sys/time.h} + \headdecl{sys/types.h} + \headdecl{unistd.h} + \funcdecl{int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set + *exceptfds, struct timeval *timeout)} Attende che uno dei file descriptor degli insiemi specificati diventi attivo. @@ -85,7 +88,7 @@ con la funzione \func{select}, il cui prototipo \end{errlist} ed inoltre \macro{ENOMEM}. } -\end{prototype} +\end{functions} La funzione mette il processo in stato di \textit{sleep} (vedi \tabref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor @@ -101,7 +104,9 @@ file descriptor, (in maniera analoga a come un \textit{signal set}, vedi manipolazione di questi \textit{file descriptor set} si possono usare delle opportune macro di preprocessore: \begin{functions} - \headdecl{sys/select.h} + \headdecl{sys/time.h} + \headdecl{sys/types.h} + \headdecl{unistd.h} \funcdecl{FD\_ZERO(fd\_set *set)} Inizializza l'insieme (vuoto). @@ -161,8 +166,10 @@ volte il tempo rimanente.\footnote{questo per 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 getire l'\textit{I/O - multiplexing}, basata sulla funzione \func{poll}, il cui prototipo è: +System V ha introdotto una sua interfaccia per gestire l'\textit{I/O + multiplexing}, basata sulla funzione \func{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 libc 5.4.28.} il cui prototipo è: \begin{prototype}{sys/poll.h} {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)} @@ -180,29 +187,216 @@ specificati da \param{ufds}. ed inoltre \macro{EFAULT} e \macro{ENOMEM}.} \end{prototype} +La funzione tiene sotto controllo un numero \param{ndfs} di file descriptor +specificati attraverso un vettore di puntatori a strutture di tipo +\type{pollfd}, la cui definizione è riportata in \figref{fig:file_pollfd}. +Come \func{select} anche \func{poll} permette di interrompere l'attesa dopo un +certo tempo, che va specificato attraverso \param{timeout} in numero di +millesecondi (un valore 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} + \end{minipage} + \normalsize + \caption{La struttura \type{pollfd}, utilizzata per specificare le modalità + di controllo di un file descriptor alla funzione \func{poll}.} + \label{fig:file_pollfd} +\end{figure} + +Per ciascun file da controllare deve essere opportunamente predisposta una +struttura \type{pollfd}; nel campo \var{fd} deve essere specificato il file +descriptor, mentre nel campo \var{events} il tipo di evento su cui si vuole +attendere; quest'ultimo deve essere specificato come maschera binaria dei +primi tre valori riportati in \tabref{tab:file_pollfd_flags} (gli altri +vengono utilizzati solo per \var{revents} come valori in uscita). + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|l|} + \hline + \textbf{Flag} & \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \macro{POLLIN} & 0x001 & È possibile la lettura immediata.\\ + \macro{POLLPRI} & 0x002 & Sono presenti dati urgenti.\\ + \macro{POLLOUT} & 0x004 & È possibile la scrittura immediata.\\ + \hline + \macro{POLLERR} & 0x008 & C'è una condizione di errore.\\ + \macro{POLLHUP} & 0x010 & Si è vericato un hung-up.\\ + \macro{POLLNVAL} & 0x020 & Il file descriptor non è aperto.\\ + \hline + \macro{POLLRDNORM}& 0x040 & Sono disponibili in lettura dati normali.\\ + \macro{POLLRDBAND}& 0x080 & Sono disponibili in lettura dati ad alta + priorità. \\ + \macro{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali. \\ + \macro{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad + alta priorità. \\ + \macro{POLLMSG} & 0x400 & Estensione propria di Linux.\\ + \hline + \end{tabular} + \caption{Costanti per l'identificazione dei vari bit dei campi + \var{events} e \var{revents} di \type{pollfd}.} + \label{tab:file_pollfd_flags} +\end{table} + +La funzione ritorna, restituendo il numero di file per i quali si è verificata +una delle condizioni di attesa richieste o un errore. Lo stato dei file +all'uscita della funzione viene restituito nel campo \var{revents} della +relativa struttura \type{pollfd}, che viene settato alla maschera binaria dei +valori riportati in \tabref{tab:file_pollfd_flags}, ed oltre alle tre +condizioni specificate tramite \var{events} può riportare anche l'occorrere di +una condizione di errore. + +Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O + multiplexing}, che è stata introdotto con le ultime revisioni dello standard +(POSIX 1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni +ad esso relative vengano dichiarate nell'header \file{sys/select.h}, che +sostituisce i precedenti, ed aggiunge a \func{select} una nuova funzione +\func{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed + l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc} + 2.0. Le \acr{libc4} e \acr{libc5} non contengono questo header, le + \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal}, + senza l'argomento \param{sigmask}, la definizione corretta è presente dalle + \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle + \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore + maggiore di 600.} il cui prototipo è: +\begin{prototype}{sys/select.h} + {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds, + struct timespec *timeout, sigset\_t *sigmask)} + + Attende che uno dei file descriptor degli insiemi specificati diventi + attivo. + + \bodydesc{La funzione in caso di successo restituisce il numero di file + descriptor (anche nullo) che sono attivi, 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 è sostanzialmente identica a \func{select}, solo che usa una +struttura \type{timespec} per indicare con maggiore precisione il timeout e +non ne aggiorna il valore in caso di interruzione, inoltre prende un argomento +aggiuntivo \param{sigmask} che è il puntatore ad una maschera di segnali (si +veda \secref{sec:sig_sigmask}). La maschera corrente viene sostituita da +questa immediatamente prima di eseguire l'attesa, e ripristinata al ritorno +della funzione. + +L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili +race condition\footnote{in Linux però, non esistendo una system call apposita, + la funzione è implementata nelle \acr{glibc} usando \func{select}, e la + possibilità di una race condition resta.} quando si deve eseguire un test su +una variabile settata da un manipolatore sulla base dell'occorrenza di un +segnale per decidere se lanciare \func{select}. Fra il test e l'esecuzione è +presente una finestra in cui potrebbe arrivare il segnale che non sarebbe +rilevato; la race condition diventa superabile disabilitando il segnale prima +del test e riabilitandolo poi grazie all'uso di \param{sigmask}. -\subsection{L'I/O asincrono} + +\subsection{L'\textsl{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}. +Una modalità alternativa all'uso dell'\textit{I/O multiplexing} è quella di +fare ricorso al cosiddetto \textsl{I/O asincrono}. Il concetto base +dell'\textsl{I/O asincrono} è che le funzioni di I/O non attendono il +completamento delle operazioni prima di ritornare, così che il processo non +viene bloccato. In questo modo diventa ad esempio possibile effettuare una +richiesta preventiva di dati, in modo da poter effettuare in contemporanea le +operazioni di calcolo e quelle di I/O. + +Abbiamo accennato in \secref{sec:file_open} che è possibile, attraverso l'uso +del flag \macro{O\_ASYNC},\footnote{l'uso del flag di \macro{O\_ASYNC} e dei + comandi \macro{F\_SETOWN} e \macro{F\_GETOWN} per \func{fcntl} è specifico + di Linux e BSD.} aprire un file in modalità asincrona, così come è possibile +attivare in un secondo tempo questa modalità settando questo flag attraverso +l'uso di \func{fcntl} con il comando \macro{F\_SETFL} (vedi +\secref{sec:file_fcntl}). + +In realtà in questo caso non si tratta di I/O asincrono vero e proprio, quanto +di un meccanismo asincrono di notifica delle variazione dello stato del file +descriptor; quello che succede è che il sistema genera un segnale (normalmente +\macro{SIGIO}, ma è possibile usarne altri) tutte le volte che diventa +possibile leggere o scrivere dal file descriptor che si è posto in questa +modalità. Si può inoltre selezionare, con il comando \macro{F\_SETOWN} di +\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale. + +Uno dei problemi che si presenta con l'implementazione usuale di questa +modalità di I/O è che essa può essere usata in maniera immediata aprendo in +modalità asincrona un solo file per processo, altrimenti ad ogni segnale si +dovrebbe provvedere ad effettuare un controllo (utilizzando di nuovo +\func{select}) su tutti i file tenuti in modalità asincrona per distinguere +quelli cui è dovuta l'emissione del segnale. + +Linux però supporta una estensione che permette di evitare tutto questo +facendo ricorso alle informazioni aggiuntive restituite attraverso la +struttura \type{siginfo\_t} quando il manipolatore del segnale viene +installato come \macro{SA\_SIGINFO} (si riveda quanto illustrato in +\secref{sec:sig_sigaction}). + +Per attivare questa caratteristica occorre settare esplicitamente il segnale +da inviare in caso di I/O asincrono (di norma sempre \macro{SIGIO}) con il +comando \macro{F\_SETSIG} di \func{fcntl}. In questo caso il manipolatore +tutte le volte che riceverà \macro{SI\_SIGIO} come valore del campo +\var{si\_code}\footnote{il valore resta \macro{SI\_SIGIO} qualunque sia il + segnale che si è associato all'I/O asincrono, ed indica appunto che il + segnale è stato generato a causa di attività nell'I/O asincrono.} di +\type{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file +descriptor che ha generato il segnale. In questo modo è possibile identificare +immediatamente il file evitando completamente l'uso di funzioni come +\func{poll} o \func{select}. Inoltre, a differenza degli altri segnali, il +sistema mantiene una coda per \macro{SIGIO}, in modo che arrivi un segnale per +ogni file attivo. + + +Benché la modalità di apertura asincrona di un file possa risultare utile in +varie occasioni (in particolar modo con i socket e gli altri file per i quali +le funzioni di I/O sono system call lente), essa è comunque limitata alla +notifica della disponibilità del file descriptor per le operazioni di I/O, e +non ad uno svolgimento asincrono delle medesime. Lo standard POSIX.1b +definisce invece una interfaccia apposita per l'I/O asincrono, che prevede un +insieme di funzioni dedicate, completamente separato rispetto a quelle usate +normalmente. + +In generale questa interfaccia è completamente astratta e può essere +implementata sia direttamente nel kernel, che attraverso l'uso di thread. Al +momento\footnote{fino ai kernel della serie 2.4.x sono presenti solo le due + alternative citate, nella serie 2.5.x è però iniziato un lavoro completo di + riscrittura di tutto il sistema di I/O, che prevede anche l'introduzione di + un nuovo layer per l'I/O asincrono.} sono disponibili due implementazioni, +una in user space, che è integrata nelle \acr{glibc}, ed una ibrida, che si +appoggia ad una estensione del kernel (il cosiddetto KAIO, non incluso nella +versione ufficiale) prodotta da SGI. Quest'ultima ha funzionalità più limitate +ma prestazioni nettamente superiori. + +Alle funzioni definite essa si può accedere includendo \file{unistd.h} e +definendo la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, mentre alla +implementazione di KAIO si accede includendo \file{linux/aio.h}; ambedue però +usano la stessa interfaccia di programmazione. -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{I/O multiplo} +\label{sec:file_multiple_io} + +Un caso abbastanza comune è quello in cui ci si trova a dover affrontare una +serie multipla di operazioni di I/O, come una serie di letture o scritture di +vari buffer. In questo caso @@ -210,8 +404,7 @@ riporta il file descriptor che ha generato il segnale. \label{sec:file_memory_map} -\subsection{I/O multiplo} -\label{sec:file_multiple_io} + diff --git a/fileunix.tex b/fileunix.tex index 37b0906..8f49c5e 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -1000,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 @@ -1037,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 diff --git a/signal.tex b/signal.tex index 1ab3bd6..5572fd4 100644 --- a/signal.tex +++ b/signal.tex @@ -1122,7 +1122,7 @@ illustrati in precedenza usare; i possibili valori sono riportati in Il valore della struttura specificata \param{value} viene usato per settare il timer, se il puntatore \param{ovalue} non è nullo il precedente valore viene salvato qui. I valori dei timer devono essere indicati attraverso una -struttura \var{itimerval}, definita in \figref{fig:file_stat_struct}. +struttura \type{itimerval}, definita in \figref{fig:file_stat_struct}. La struttura è composta da due membri, il primo, \var{it\_interval} definisce il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla @@ -1146,7 +1146,7 @@ struct itimerval \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \var{itimerval}, che definisce i valori dei timer di + \caption{La struttura \type{itimerval}, che definisce i valori dei timer di sistema.} \label{fig:sig_itimerval} \end{figure} @@ -1865,7 +1865,7 @@ manipolatore, da specificare, a seconda dell'uso o meno del flag implementazioni questi vengono addirittura definiti come \ctyp{union}): la prima è quella classica usata anche con \func{signal}, la seconda permette invece di usare un manipolatore in grado di ricevere informazioni più -dettagliate dal sistema, attraverso la struttura \var{siginfo\_t}, riportata +dettagliate dal sistema, attraverso la struttura \type{siginfo\_t}, riportata in \figref{fig:sig_siginfo_t}. \begin{figure}[!htb] @@ -1891,7 +1891,7 @@ siginfo_t { \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \var{siginfo\_t}.} + \caption{La struttura \type{siginfo\_t}.} \label{fig:sig_siginfo_t} \end{figure}