BSD4.2 ed è stata standardizzata in BSD4.4, in seguito è stata portata su
tutti i sistemi che supportano i socket, compreso le varianti di System V ed
inserita in POSIX.1-2001; il suo prototipo è:\footnote{l'header
- \texttt{sys/select.h} è stato introdotto con POSIX.1-2001, in precedenza
- occorreva includere \texttt{sys/time.h}, \texttt{sys/types.h} e
- \texttt{unistd.h}.}
+ \texttt{sys/select.h} è stato introdotto con POSIX.1-2001, è ed presente con
+ le \acr{glibc} a partire dalla versione 2.0, in precedenza, con le
+ \acr{libc4} e le \acr{libc5}, occorreva includere \texttt{sys/time.h},
+ \texttt{sys/types.h} e \texttt{unistd.h}.}
\begin{funcproto}{
\fhead{sys/select.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 (ad esempio in Linux, 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, questo limite è stato rimosso, esso
-indica le dimensioni massime dei numeri usati nei \textit{file descriptor
- set}, ed il suo valore, secondo lo standard POSIX 1003.1-2001, è definito in
+serie 2.0.x, c'era un limite di 256 file per processo), ma da quando, nelle
+versioni più recenti del kernel, questo limite è stato rimosso, esso indica le
+dimensioni massime dei numeri usati nei \textit{file descriptor set}, ed il
+suo valore, secondo lo standard POSIX 1003.1-2001, è definito in
\headfile{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; allo stesso modo
+inizializzato può dar luogo a comportamenti non prevedibili. Allo stesso modo
usare \macro{FD\_SET} o \macro{FD\_CLR} con un file descriptor il cui valore
eccede \const{FD\_SETSIZE} può dare luogo ad un comportamento indefinito.
il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
effettuare una lettura,\footnote{per essere precisi la funzione ritornerà in
tutti i casi in cui la successiva esecuzione di \func{read} risulti non
- bloccante, quindi anche in caso di \textit{end-of-file}; inoltre con Linux
- possono verificarsi casi particolari, ad esempio quando arrivano dati su un
- socket dalla rete che poi risultano corrotti e vengono scartati, può
- accadere che \func{select} riporti il relativo file descriptor come
- leggibile, ma una successiva \func{read} si blocchi.} il secondo,
+ bloccante, quindi anche in caso di \textit{end-of-file}.} il secondo,
\param{writefds}, per verificare la possibilità di effettuare una scrittura ed
-il terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
-dati urgenti \itindex{out-of-band} su un socket, vedi
+il terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni come i
+dati urgenti \itindex{out-of-band} su un socket, (vedi
sez.~\ref{sec:TCP_urgent_data}).
Dato che in genere non si tengono mai sotto controllo fino a
-\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
+\const{FD\_SETSIZE} file contemporaneamente, la funzione richiede di
specificare qual è il valore più alto fra i 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{ndfs}, che
-deve corrispondere al valore massimo aumentato di uno.\footnote{si ricordi che
- i file descriptor sono numerati progressivamente a partire da zero, ed il
- valore indica il numero più alto fra quelli da tenere sotto controllo;
- dimenticarsi di aumentare di uno il valore di \param{ndfs} è un errore
- comune.}
-
-Infine l'argomento \param{timeout}, espresso con una struttura di tipo
-\struct{timeval} (vedi fig.~\ref{fig:sys_timeval_struct}) specifica un tempo
-massimo di attesa 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 numero di file descriptor pronti,\footnote{questo è
- il comportamento previsto dallo standard, ma la standardizzazione della
- funzione è recente, ed esistono ancora alcune versioni di Unix che non si
- comportano in questo modo.} e ciascun insieme viene sovrascritto per
-indicare quali sono i file descriptor pronti per le operazioni ad esso
-relative, in modo da poterli controllare con \macro{FD\_ISSET}. Se invece si
-ha un timeout viene restituito un valore nullo e gli insiemi non vengono
-modificati. In caso di errore la funzione restituisce -1, ed i valori dei tre
-insiemi sono indefiniti e non si può fare nessun affidamento sul loro
-contenuto.
+deve corrispondere al valore massimo aumentato di uno. Si ricordi infatti che
+i file descriptor sono numerati progressivamente a partire da zero, ed il
+valore indica il numero più alto fra quelli da tenere sotto controllo,
+dimenticarsi di aumentare di uno il valore di \param{ndfs} è un errore comune.
+
+Infine l'argomento \param{timeout}, espresso con il puntatore ad una struttura
+di tipo \struct{timeval} (vedi fig.~\ref{fig:sys_timeval_struct}) specifica un
+tempo massimo di attesa 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, e così può essere utilizzata eseguire il \itindex{polling}
+\textit{polling} su un gruppo di file descriptor. Usare questo argomento con
+tutti i \textit{file descriptor set} vuoti è un modo portabile, disponibile
+anche su sistemi in cui non sono disponibili le funzioni avanzate di
+sez.~\ref{sec:sig_timer_adv}, per tenere un processo in stato di
+\textit{sleep} con precisioni inferiori al secondo.
+
+In caso di successo la funzione restituisce il numero di file descriptor
+pronti, seguendo il comportamento previsto dallo standard
+POSIX.1-2001,\footnote{si tenga però presente che esistono alcune versioni di
+ Unix che non si comportano in questo modo, restituendo un valore positivo
+ generico.} e ciascun insieme viene sovrascritto per indicare quali sono i
+file descriptor pronti per le operazioni ad esso relative, in modo da poterli
+controllare con \macro{FD\_ISSET}. Se invece scade il tempo indicato
+da \param{timout} viene restituito un valore nullo e i \textit{file descriptor
+ set} non vengono modificati. In caso di errore la funzione restituisce -1, i
+valori dei tre insiemi e di \param{timeout} sono indefiniti e non si può fare
+nessun affidamento sul loro contenuto; nelle versioni più recenti della
+funzione invece i \textit{file descriptor set} non vengono modificati anche in
+caso di errore.
+
+Si tenga presente infine che su Linux, in caso di programmazione
+\textit{multithread} se un file descriptor viene chiuso in un altro
+\textit{thread} rispetto a quello in cui si sta usando \func{select}, questa
+non subisce nessun effetto. In altre varianti di sistemi unix-like invece
+\func{select} ritorna indicando che il file descriptor è pronto, con
+conseguente possibile errore nel caso lo si usi senza che sia stato
+riaperto. Lo standard non prevede niente al riguardo e non si deve dare per
+assunto nessuno dei due comportamenti se si vogliono scrivere programmi
+portabili.
+
\itindend{file~descriptor~set}
-Una volta ritornata la funzione si potrà controllare quali sono i file
-descriptor pronti ed operare su di essi, si tenga presente però che si tratta
-solo di un suggerimento, esistono infatti condizioni\footnote{ad esempio
- quando su un socket arrivano dei dati che poi vengono scartati perché
- corrotti.} in cui \func{select} può riportare in maniera spuria che un file
-descriptor è pronto in lettura, quando una successiva lettura si bloccherebbe.
-Per questo quando si usa \textit{I/O multiplexing} è sempre raccomandato l'uso
-delle funzioni di lettura e scrittura in modalità non bloccante.
-
-In Linux \func{select} modifica anche il valore di \param{timeout},
-impostandolo al tempo restante, 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. Questo può causare problemi di portabilità sia
-quando si usa 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.\footnote{in
- genere questa caratteristica è disponibile nei sistemi che derivano da
- System V e non è disponibile per quelli che derivano da BSD; lo standard
- POSIX.1-2001 non permette questo comportamento.}
+Una volta ritornata la funzione, si potrà controllare quali sono i file
+descriptor pronti, ed operare su di essi. Si tenga presente però che
+\func{select} fornisce solo di un suggerimento, esistono infatti condizioni in
+cui \func{select} può riportare in maniera spuria che un file descriptor è
+pronto, ma l'esecuzione di una operazione di I/O si bloccherebbe: ad esempio
+con Linux questo avviene quando su un socket arrivano dei dati che poi vengono
+scartati perché corrotti (ma sono possibili pure altri casi); in tal caso pur
+risultando il relativo file descriptor pronto in lettura una successiva
+esecuzione di una \func{read} si bloccherebbe. Per questo motivo quando si usa
+l'\textit{I/O multiplexing} è sempre raccomandato l'uso delle funzioni di
+lettura e scrittura in modalità non bloccante.
+
+Su Linux quando la \textit{system call} \func{select} viene interrotta da un
+segnale modifica il valore nella struttura puntata da \param{timeout},
+impostandolo al tempo restante. In tal caso infatti si ha un errore di
+\errcode{EINTR} ed occorre rilanciare la funzione per proseguire l'attesa, ed
+in questo modo non è necessario ricalcolare tutte le volte il tempo
+rimanente. Questo può causare problemi di portabilità sia quando si usa 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 questa caratteristica è
+disponibile nei sistemi che derivano da System V e non è disponibile per
+quelli che derivano da BSD; lo standard POSIX.1-2001 non permette questo
+comportamento e per questo motivo le \acr{glibc} nascondono il comportamento
+passando alla \textit{system call} una copia dell'argomento \param{timeout}.
Uno dei problemi che si presentano con l'uso di \func{select} è che il suo
comportamento dipende dal valore del file descriptor che si vuole tenere sotto
\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} assumerà uno dei valori:
+
+\begin{funcproto}{
+\fhead{sys/select.h}
+\fdecl{int pselect(int n, fd\_set *readfds, fd\_set *writefds,
+ fd\_set *exceptfds, \\
+\phantom{int pselect(}struct timespec *timeout, sigset\_t *sigmask)}
+\fdesc{Attende che uno dei file descriptor degli insiemi specificati diventi
+ attivo.}
+}
+{La funzione ritorna il numero (anche nullo) di file descriptor che sono
+ attivi in caso di successo e $-1$ per un errore, nel qual caso \var{errno}
+ assumerà uno dei valori:
\begin{errlist}
\item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno
degli insiemi.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
\item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
o un valore non valido per \param{timeout}.
- \end{errlist}
- ed inoltre \errval{ENOMEM}.}
-\end{prototype}
+ \end{errlist}
+ ed inoltre \errval{ENOMEM} nel suo significato generico.
+}
+\end{funcproto}
La funzione è sostanzialmente identica a \func{select}, solo che usa una
struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timespec_struct}) per
indicare con maggiore precisione il timeout e non ne aggiorna il valore in
-caso di interruzione.\footnote{in realtà la \textit{system call} di Linux
- aggiorna il valore al tempo rimanente, ma la funzione fornita dalle
- \acr{glibc} modifica questo comportamento passando alla \textit{system call}
- una variabile locale, in modo da mantenere l'aderenza allo standard POSIX
- che richiede che il valore di \param{timeout} non sia modificato.} Inoltre
-prende un argomento aggiuntivo \param{sigmask} che è il puntatore ad una
-\index{maschera~dei~segnali} maschera di segnali (si veda
+caso di interruzione. In realtà anche in questo caso la \textit{system call}
+di Linux aggiorna il valore al tempo rimanente, ma la funzione fornita dalle
+\acr{glibc} modifica questo comportamento passando alla \textit{system call}
+una variabile locale, in modo da mantenere l'aderenza allo standard POSIX che
+richiede che il valore di \param{timeout} non sia modificato. Ma rispetto a
+\func{select} prende un argomento aggiuntivo \param{sigmask} che è il
+puntatore ad una \index{maschera~dei~segnali} maschera di segnali (si veda
sez.~\ref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
funzione.