Aggiunta nota sul self-pipe trick ed un po' di indici
authorSimone Piccardi <piccardi@gnulinux.it>
Tue, 28 Dec 2004 00:08:24 +0000 (00:08 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Tue, 28 Dec 2004 00:08:24 +0000 (00:08 +0000)
fileadv.tex
signal.tex

index f4ccd79ade39d6c3a482d7f16498e362c9b5a368..de7ae5d50ae1aa153e836965c4ffd8691b579a3a 100644 (file)
@@ -59,18 +59,17 @@ da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
 potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}.
 
 Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento delle funzioni di I/O aprendo un file in quella
-che viene chiamata \textsl{modalità non-bloccante}, attraverso l'uso del flag
-\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni
-di input/output eseguite sul file che si sarebbero bloccate, ritornano
-immediatamente, restituendo l'errore \errcode{EAGAIN}.
-
-L'utilizzo di questa modalità di I/O permette di risolvere il problema
-controllando a turno i vari file descriptor, in un ciclo in cui si ripete
-l'accesso fintanto che esso non viene garantito.  Ovviamente questa tecnica,
-detta \textit{polling}\index{polling}, è estremamente inefficiente: si tiene
-costantemente impiegata la CPU solo per eseguire in continuazione delle system
-call che nella gran parte dei casi falliranno. 
+questo tipo di comportamento delle funzioni di I/O aprendo un file in
+\textsl{modalità non-bloccante}, attraverso l'uso del flag \const{O\_NONBLOCK}
+nella chiamata di \func{open}. In questo caso le funzioni di input/output
+eseguite sul file che si sarebbero bloccate, ritornano immediatamente,
+restituendo l'errore \errcode{EAGAIN}.  L'utilizzo di questa modalità di I/O
+permette di risolvere il problema controllando a turno i vari file descriptor,
+in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
+Ovviamente questa tecnica, detta \textit{polling}\index{polling}, è
+estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
+eseguire in continuazione delle system call che nella gran parte dei casi
+falliranno.
 
 Per superare questo problema è stato introdotto il concetto di \textit{I/O
   multiplexing}, una nuova modalità di operazioni che consenta di tenere sotto
@@ -89,11 +88,11 @@ ulteriori dettagli e qualche esempio in sez.~\ref{sec:TCP_sock_multiplexing}.
 \subsection{Le funzioni \func{select} e \func{pselect}}
 \label{sec:file_select}
 
-Il primo ad introdurre una interfaccia per l'\textit{I/O multiplexing} è stato
-BSD,\footnote{la funzione \func{select} è 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 è:
+Il primo kernel unix-like ad introdurre una interfaccia per l'\textit{I/O
+  multiplexing} è stato BSD,\footnote{la funzione \func{select} è 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}
@@ -127,7 +126,8 @@ degli insiemi specificati (\param{readfds}, \param{writefds} e
 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 \textit{signal set} (vedi
+file descriptor, in maniera analoga a come un 
+\index{\textit{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:
@@ -179,23 +179,23 @@ 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 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.
+  il valore di \param{n} è un errore comune.}  Infine l'argomento
+\param{timeout}, 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 i file descriptor pronti per le operazioni ad esso relative, in modo
-da poterli controllare con \const{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.
+indicare quali sono i file descriptor pronti per le operazioni ad esso
+relative, in modo da poterli controllare con \const{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.
 
 In Linux \func{select} modifica anche il valore di \param{timeout},
 impostandolo al tempo restante in caso di interruzione prematura; questo è
@@ -269,13 +269,10 @@ funzione.
 
 L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
 race condition\index{race condition} quando ci si deve porre in attesa sia di
-un segnale che di dati.\footnote{in Linux però non è stata ancora introdotta
-  la relativa system call, pertanto la funzione è implementata nelle
-  \acr{glibc} attraverso \func{select} e la possibilità di race condition
-  permane.} La tecnica classica è quella di utilizzare il gestore per
-impostare una variabile globale e controllare questa nel corpo principale del
-programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci spazio
-a possibili race condition, per cui diventa essenziale utilizzare
+un segnale che di dati. La tecnica classica è quella di utilizzare il gestore
+per impostare una variabile globale e controllare questa nel corpo principale
+del programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci
+spazio a possibili race condition, per cui diventa essenziale utilizzare
 \func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire
 il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde
 evitare l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe
@@ -291,15 +288,24 @@ condition,\index{race condition} perch
 chiamata a \func{select}, questa non verrà interrotta, e la ricezione del
 segnale non sarà rilevata.
 
-Per questo è stata introdotta \func{pselect}, che attraverso l'argomento
+Per questo è stata introdotta \func{pselect} che attraverso l'argomento
 \param{sigmask} permette di riabilitare la ricezione il segnale
-contestualmente all'esecuzione della funzione, e ribloccandolo non appena essa
-ritorna. In questo modo il precedente codice potrebbe essere modificato
-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.
+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 race condition permane; esiste però una soluzione,
+  chiamata \index{\textit{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.
 
 
 
@@ -315,12 +321,12 @@ cui prototipo 
 \begin{prototype}{sys/poll.h}
   {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
   
-  La funzione attende un cambiamento di stato per uno dei file descriptor
-  specificati da \param{ufds}.
+  La funzione attende un cambiamento di stato su un insieme di file
+  descriptor.
   
   \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:
+    in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
+    ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
   \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
     degli insiemi.
@@ -336,8 +342,8 @@ file descriptor, specificati attraverso il puntatore \param{ufds} ad un
 vettore di strutture \struct{pollfd}.  Come con \func{select} si può
 interrompere l'attesa dopo un certo tempo, questo deve essere specificato con
 l'argomento \param{timeout} in numero di millisecondi: un valore negativo
-indica un'attesa indefinita, mentre un valore comporta il ritorno immediato (e
-può essere utilizzato per impiegare \func{poll} in modalità
+indica un'attesa indefinita, mentre un valore nullo comporta il ritorno
+immediato (e può essere utilizzato per impiegare \func{poll} in modalità
 \textsl{non-bloccante}).
 
 \begin{figure}[!htb]
index a8de40a995f1df471b88706afb946a2d6b774a25..e8efc45ef2f79a250016d7f1ff37e27bd48e566e 100644 (file)
@@ -1563,10 +1563,10 @@ quale potr
 segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}).
 
 Questo è il tipico esempio di caso, già citato in
-sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition\index{race
-  condition}; se infatti il segnale arriva immediatamente dopo l'esecuzione
-del controllo (\texttt{\small 6}) ma prima della cancellazione del flag
-(\texttt{\small 7}), la sua occorrenza sarà perduta.
+sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition 
+\index{race condition}; se infatti il segnale arriva immediatamente dopo
+l'esecuzione del controllo (\texttt{\small 6}) ma prima della cancellazione
+del flag (\texttt{\small 7}), la sua occorrenza sarà perduta.
 
 Questi esempi ci mostrano che per una gestione effettiva dei segnali occorrono
 funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla
@@ -1587,9 +1587,10 @@ pendenti.  Per questo motivo lo standard POSIX.1, insieme alla nuova semantica
 dei segnali ha introdotto una interfaccia di gestione completamente nuova, che
 permette di ottenete un controllo molto più dettagliato. In particolare lo
 standard ha introdotto un nuovo tipo di dato \type{sigset\_t}, che permette di
-rappresentare un \textsl{insieme di segnali} (un \textit{signal set}, come
-viene usualmente chiamato), che è il tipo di dato che viene usato per gestire
-il blocco dei segnali.
+rappresentare un \textsl{insieme di segnali} (un 
+\index{\textit{signal set}}\textit{signal set}, come viene usualmente
+chiamato), che è il tipo di dato che viene usato per gestire il blocco dei
+segnali.
 
 In genere un \textsl{insieme di segnali} è rappresentato da un intero di
 dimensione opportuna, di solito si pari al numero di bit dell'architettura