Per specificare quali file descriptor si intende \textsl{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
-\itindex{signal~set}\textit{signal set} (vedi sez.~\ref{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:
+file descriptor, in maniera analoga a come un \itindex{signal~set}
+\textit{signal set} (vedi sez.~\ref{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/time.h}
\headdecl{sys/types.h}
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.
-\itindend{file~descriptor~set}
La funzione restituisce il numero di file descriptor pronti,\footnote{questo è
il comportamento previsto dallo standard, ma la standardizzazione della
insiemi sono indefiniti e non si può fare nessun affidamento sul loro
contenuto.
+\itindend{file~descriptor~set}
+
In Linux \func{select} modifica anche il valore di \param{timeout},
impostandolo al tempo restante in caso di interruzione prematura; questo è
utile quando la funzione viene interrotta da un segnale, in tal caso infatti
Per questo è stata introdotta \func{pselect} che attraverso l'argomento
\param{sigmask} permette di riabilitare la ricezione il segnale
-contestualmente all'esecuzione della funzione,\footnote{in Linux però non è
- presente la relativa system call, e la funzione è implementata nelle
- \acr{glibc} attraverso \func{select} (vedi \texttt{man select\_tut}) per cui
- la possibilità di \itindex{race~condition}\textit{race condition} permane;
- esiste però una soluzione, chiamata \itindex{self-pipe trick}
- \textit{self-pipe trick}, che consiste nell'aprire una pipe (vedi
- sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in lettura della
- stessa, e indicare l'arrivo di un segnale scrivendo sul capo in scrittura
- all'interno del manipolatore; in questo modo anche se il segnale va perso
- prima della chiamata di \func{select} questa lo riconoscerà comunque dalla
- presenza di dati sulla pipe.} ribloccandolo non appena essa ritorna, così
-che il precedente codice potrebbe essere riscritto nel seguente modo:
+contestualmente all'esecuzione della funzione,\footnote{in Linux però, fino al
+ kernel 2.6.26, non è presente la relativa system call, e la funzione è
+ implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man
+ select\_tut}) per cui la possibilità di \itindex{race~condition}
+ \textit{race condition} permane; esiste però una soluzione, chiamata
+ \itindex{self-pipe trick} \textit{self-pipe trick}, che consiste nell'aprire
+ una pipe (vedi sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in
+ lettura della stessa, e indicare l'arrivo di un segnale scrivendo sul capo
+ in scrittura all'interno del manipolatore; in questo modo anche se il
+ segnale va perso prima della chiamata di \func{select} questa lo riconoscerà
+ comunque dalla presenza di dati sulla pipe.} ribloccandolo non appena essa
+ritorna, così che il precedente codice potrebbe essere riscritto nel seguente
+modo:
\includecodesnip{listati/pselect_norace.c}
in questo caso utilizzando \var{oldmask} durante l'esecuzione di
\func{pselect} la ricezione del segnale sarà abilitata, ed in caso di
interruzione si potranno eseguire le relative operazioni.
% TODO pselect è stata introdotta nel kernel 2.6.16 (o 15 o 17?) insieme a
-% ppoll mettere e verificare
+% ppoll mettere e verificare, vedi articolo LWN http://lwn.net/Articles/176750/
\subsection{La funzione \func{poll}}
sappiamo che la funzione ritorna quando uno o più dei file descriptor messi
sotto controllo è pronto per la relativa operazione.
+
+
In quell'occasione non abbiamo però definito cosa si intende per pronto,
infatti per dei normali file, o anche per delle pipe, la condizione di essere
pronti per la lettura o la scrittura è ovvia; invece lo è molto meno nel caso
dei socket, visto che possono intervenire tutte una serie di possibili
condizioni di errore dovute alla rete. Occorre allora specificare chiaramente
quali sono le condizioni per cui un socket risulta essere ``\textsl{pronto}''
-quando viene passato come membro di uno dei tre \textit{file descriptor set}
-usati da \func{select}.
+quando viene passato come membro di uno dei tre \itindex{file~descriptor~set}
+\textit{file descriptor set} usati da \func{select}.
Le condizioni che fanno si che la funzione \func{select} ritorni segnalando
che un socket (che sarà riportato nel primo insieme di file descriptor) è
non si bloccherà ma restituirà una condizione di errore (ad esempio
\func{read} restituirà -1) e imposterà la variabile \var{errno} al relativo
valore. Vedremo in sez.~\ref{sec:sock_generic_options} come sia possibile
- estrarre e cancellare errori pendenti su un socket usando l'opzione
- \const{SO\_ERROR}.
+ estrarre e cancellare gli errori pendenti su un socket senza usare
+ \func{read} usando l'opzione \const{SO\_ERROR}.
\item quando si sta utilizzando un \textit{listening socket} ed ci sono delle
connessioni completate. In questo caso la funzione \func{accept} non si
bloccherà.\footnote{in realtà questo non è sempre vero, come accennato in
allegati alla guida.
In questo caso la funzione comincia (\texttt{\small 8--9}) con l'azzeramento
-del file descriptor set \var{fset} e l'impostazione del valore \var{maxfd}, da
-passare a \func{select} come massimo per il numero di file descriptor. Per
-determinare quest'ultimo si usa la macro \code{max} definita nel nostro file
-\file{macro.h} che raccoglie una collezione di macro di preprocessore di varia
-utilità.
+del \itindex{file~descriptor~set} \textit{file descriptor set} \var{fset} e
+l'impostazione del valore \var{maxfd}, da passare a \func{select} come massimo
+per il numero di file descriptor. Per determinare quest'ultimo si usa la macro
+\code{max} definita nel nostro file \file{macro.h} che raccoglie una
+collezione di macro di preprocessore di varia utilità.
La funzione prosegue poi (\texttt{\small 10--41}) con il ciclo principale, che
viene ripetuto indefinitamente. Per ogni ciclo si reinizializza
-(\texttt{\small 11--12}) il file descriptor set, impostando i valori per il
-file descriptor associato al socket \var{socket} e per lo standard input (il
-cui valore si recupera con la funzione \func{fileno}). Questo è necessario in
-quanto la successiva (\texttt{\small 13}) chiamata a \func{select} comporta
-una modifica dei due bit relativi, che quindi devono essere reimpostati
-all'inizio di ogni ciclo.
+(\texttt{\small 11--12}) il \itindex{file~descriptor~set} \textit{file
+ descriptor set}, impostando i valori per il file descriptor associato al
+socket \var{socket} e per lo standard input (il cui valore si recupera con la
+funzione \func{fileno}). Questo è necessario in quanto la successiva
+(\texttt{\small 13}) chiamata a \func{select} comporta una modifica dei due
+bit relativi, che quindi devono essere reimpostati all'inizio di ogni ciclo.
Si noti come la chiamata a \func{select} venga eseguita usando come primo
argomento il valore di \var{maxfd}, precedentemente calcolato, e passando poi
-il solo file descriptor set per il controllo dell'attività in lettura, negli
-altri argomenti sono passati tutti puntatori nulli, non interessando né il
-controllo delle altre attività, né l'impostazione di un valore di timeout.
+il solo \itindex{file~descriptor~set} \textit{file descriptor set} per il
+controllo dell'attività in lettura, negli altri argomenti sono passati tutti
+puntatori nulli, non interessando né il controllo delle altre attività, né
+l'impostazione di un valore di timeout.
Al ritorno di \func{select} si provvede a controllare quale dei due file
descriptor presenta attività in lettura, cominciando (\texttt{\small 14--24})
non nullo, dopo di che (\texttt{\small 20}) si effettua la chiusura del lato
in scrittura del socket con \func{shutdown}. Infine (\texttt{\small 21}) si
usa la macro \macro{FD\_CLR} per togliere lo standard input dal file
-descriptor set.
+descriptor set. \itindex{file~descriptor~set}
In questo modo anche se la lettura del file in ingresso è conclusa, la
funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua
alto.} che verrà anche (\texttt{\small 4}) inserito nella tabella.
La prima sezione (\texttt{\small 7--10}) del ciclo principale esegue la
-costruzione del \textit{file descriptor set} \var{fset} in base ai socket
-connessi in un certo momento; all'inizio ci sarà soltanto il socket in
-ascolto, ma nel prosieguo delle operazioni, verranno utilizzati anche tutti i
-socket connessi registrati nella tabella \var{fd\_open}. Dato che la chiamata
-di \func{select} modifica il valore del \textit{file descriptor set}, è
-necessario ripetere (\texttt{\small 7}) ogni volta il suo azzeramento, per poi
-procedere con il ciclo (\texttt{\small 8--10}) in cui si impostano i socket
-trovati attivi.
+costruzione del \itindex{file~descriptor~set} \textit{file descriptor set}
+\var{fset} in base ai socket connessi in un certo momento; all'inizio ci sarà
+soltanto il socket in ascolto, ma nel prosieguo delle operazioni, verranno
+utilizzati anche tutti i socket connessi registrati nella tabella
+\var{fd\_open}. Dato che la chiamata di \func{select} modifica il valore del
+\itindex{file~descriptor~set} \textit{file descriptor set}, è necessario
+ripetere (\texttt{\small 7}) ogni volta il suo azzeramento, per poi procedere
+con il ciclo (\texttt{\small 8--10}) in cui si impostano i socket trovati
+attivi.
Per far questo si usa la caratteristica dei file descriptor, descritta in
sez.~\ref{sec:file_open}, per cui il kernel associa sempre ad ogni nuovo file
(\texttt{\small 29--55}) fintanto che il numero di socket attivi \var{n} resta
diverso da zero; in questo modo se l'unico socket con attività era quello
connesso, avendo opportunamente decrementato il contatore, il ciclo verrà
-saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del file
-descriptor set con i nuovi valori nella tabella) alla chiamata di
-\func{accept}. Se il socket attivo non è quello in ascolto, o ce ne sono
-comunque anche altri, il valore di \var{n} non sarà nullo ed il controllo sarà
-eseguito. Prima di entrare nel ciclo comunque si inizializza (\texttt{\small
- 28}) il valore della variabile \var{i} che useremo come indice nella tabella
-\var{fd\_open} al valore minimo, corrispondente al file descriptor del socket
-in ascolto.
+saltato, e si ritornerà immediatamente (ripetuta l'inizializzazione del
+\itindex{file~descriptor~set} file descriptor set con i nuovi valori nella
+tabella) alla chiamata di \func{accept}. Se il socket attivo non è quello in
+ascolto, o ce ne sono comunque anche altri, il valore di \var{n} non sarà
+nullo ed il controllo sarà eseguito. Prima di entrare nel ciclo comunque si
+inizializza (\texttt{\small 28}) il valore della variabile \var{i} che useremo
+come indice nella tabella \var{fd\_open} al valore minimo, corrispondente al
+file descriptor del socket in ascolto.
Il primo passo (\texttt{\small 30}) nella verifica è incrementare il valore
dell'indice \var{i} per posizionarsi sul primo valore possibile per un file
queste problematiche con i socket. Abbiamo però visto in
sez.~\ref{sec:file_multiplexing} come la funzione \func{poll} possa costituire
una alternativa a \func{select}, con alcuni vantaggi.\footnote{non soffrendo
- delle limitazioni dovute all'uso dei \textit{file descriptor set}.}
+ delle limitazioni dovute all'uso dei \itindex{file~descriptor~set}
+ \textit{file descriptor set}.}
Ancora una volta in sez.~\ref{sec:file_poll} abbiamo trattato la funzione in
maniera generica, parlando di file descriptor, ma come per \func{select}
uscita e notifica in caso si errore (\texttt{\small 49--52}).
Come si può notare la logica del programma è identica a quella vista in
-fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; la
-sola differenza significativa è che in questo caso non c'è bisogno di
-rigenerare i file descriptor set in quanto l'uscita è indipendente dai dati in
-ingresso. Si applicano comunque anche a questo server le considerazioni finali
-di sez.~\ref{sec:TCP_serv_select}.
+fig.~\ref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select};
+la sola differenza significativa è che in questo caso non c'è bisogno di
+rigenerare i \itindex{file~descriptor~set} file descriptor set in quanto
+l'uscita è indipendente dai dati in ingresso. Si applicano comunque anche a
+questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}.
% LocalWords: socket TCP client dell'I multiplexing stream three way handshake