\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale.
In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select}
-che normalmente quando vengono usate con un grande numero di file descriptor,
-non hanno buone prestazioni, in quanto passano maggior parte del tempo ad
-eseguire uno scan per determinare quali sono quelli (in genere un piccola
+che, quando vengono usate con un numero molto grande di file descriptor, non
+hanno buone prestazioni. In tal caso infatti la maggior parte del loro tempo
+di esecuzione è impegato per eseguire uno scan su tutti i file descriptor
+tenuti sotto controllo per determinare quali sono quelli (in genere un piccola
percentuale) che sono diventati attivi.
-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{poll} o \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 utilizzare le funzionalità dei
-segnali real-time (vedi \secref{sec:sig_real_time}) settando esplicitamente con
-il comando \macro{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare
-in caso di I/O asincrono (di norma viene usato \macro{SIGIO}). In questo caso
-il manipolatore tutte le volte che riceverà \macro{SI\_SIGIO} come valore del
+Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
+presenta notevoli problemi, dato che non è possibile determinare, quando sono
+più di uno, qual'è il file descriptor responsabile dell'emissione del segnale.
+Linux però supporta le estensioni POSIX.1b dei segnali che permettono di
+superare il problema facendo ricorso alle informazioni aggiuntive restituite
+attraverso la struttura \type{siginfo\_t}, utilizzando la forma estesa
+\var{sa\_sigaction} del manipolatore (si riveda quanto illustrato in
+\secref{sec:sig_sigaction}).
+
+Per far questo però occorre utilizzare le funzionalità dei segnali real-time
+(vedi \secref{sec:sig_real_time}) settando esplicitamente con il comando
+\macro{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
+I/O asincrono (il segnale di default è \macro{SIGIO}). In questo caso il
+manipolatorem 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}.
+descriptor che ha generato il segnale.
+
+Un secondo vantaggio dell'uso dei segnali real-time è che essendo dotati di
+una coda di consegna ogni segnale sarà associato ad uno solo file descriptor;
+inoltre sarà possibile stabilire delle priorità nella risposta a seconda del
+segnale usato. In questo modo si può identificare immediatamente un file su
+cui l'accesso è diventato possibile evitando completamente l'uso di funzioni
+come \func{poll} e \func{select}.
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
+definisce anche una interfaccia apposita per l'I/O asincrono, che prevede un
+insieme di funzioni dedicate, completamente separate rispetto a quelle usate
normalmente.
In generale questa interfaccia è completamente astratta e può essere
di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, 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.} esiste una sola versione stabile, quella delle \acr{glibc}, che
-è realizzata completamente in user space; esistono comunque vari progetti
-(come il KAIO della SGI, o i patch di Benjamin La Haise) che prevedono un
-supporto diretto all'interno del kernel.
+ asincrono.} esiste una sola versione stabile di questa interfaccia, quella
+delle \acr{glibc}, che è realizzata completamente in user space. Esistono
+comunque vari progetti sperimentali (come il KAIO della SGI, o i patch di
+Benjamin La Haise) che prevedono una interfaccia che utilizza un supporto
+diretto da parte del kernel.
Come si può notare in \figref{fig:sig_sigaction} \func{sigaction}
permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ed è
- stata aggiunta a partire dai kernel della serie 2.1.x con l'introduzione dei
- segnali real-time (vedi \secref{sec:sig_real_time}). In precedenza era
- possibile ottenere alcune informazioni addizionali usando \var{sa\_handler}
- con un secondo parametro addizionale di tipo \var{struct sigcontext}, che
- adesso è deprecato.} di utilizzare due forme diverse di manipolatore, da
+ stata aggiunta nei kernel della serie 2.1.x con l'introduzione dei segnali
+ real-time (vedi \secref{sec:sig_real_time}). In precedenza era possibile
+ ottenere alcune informazioni addizionali usando \var{sa\_handler} con un
+ secondo parametro addizionale di tipo \var{struct sigcontext}, che adesso è
+ deprecato.} di utilizzare due forme diverse di manipolatore, da
specificare, a seconda dell'uso o meno del flag \macro{SA\_SIGINFO},
rispettivamente attraverso i campi \var{sa\_sigaction} o \var{sa\_handler},
(che devono essere usati in maniera alternativa, in certe implementazioni
Installando un manipolatore di tipo \var{sa\_sigaction} diventa allora
possibile accedere alle informazioni restituite attraverso il puntatore a
questa struttura. Tutti i segnali settano i campi \var{si\_signo}, che riporta
-il segnale ricevuto, \var{si\_errno}, che riporta il codice di errore, e
-\var{si\_code}, che viene usato per indicare la ragione per cui è stato emesso
-il segnale (come i dettagli sul tipo di errore per \macro{SIGFPE} e
-\macro{SIGILL}) ed ha valori diversi\footnote{un elenco dettagliato è
- disponibile nella man page di \func{sigaction}.} a seconda del tipo di
-segnale ricevuto.
-
-Il resto della struttura può essere definito come \ctyp{union} ed i valori
+il numero del segnale ricevuto, \var{si\_errno}, che riporta, quando diverso
+da zero, il codice dell'errore associato al segnale, e \var{si\_code}, che
+viene usato dal kernel per specificare maggiori dettagli riguardo l'evento che
+ha causato l'emissione del segnale.
+
+In generale \var{si\_code} contiene, per i segnali generici, per quelli
+real-time e per tutti quelli inviati tramite \func{kill}, informazioni circa
+l'origine del segnale (se generato dal kernel, da un timer, da \func{kill},
+ecc.). Alcuni segnali però usano \var{si\_code} per fornire una informazione
+specifica: ad esempio i vari segnali di errore (\macro{SIGFPE},
+\macro{SIGILL}, \macro{SIGBUS} e \macro{SIGSEGV}) lo usano per fornire
+maggiori dettagli riguardo l'errore (come il tipo di errore aritmetico, di
+istruzione illecita o di violazione di memoria) mentre alcuni segnali di
+controllo (\macro{SIGCHLD}, \macro{SIGTRAP} e \macro{SIGPOLL}) forniscono
+altre informazioni speecifiche. In tutti i casi il valore del campo è
+riportato attraverso delle costanti (le cui definizioni si trovano
+\file{bits/siginfo.h}) il cui elenco dettagliato è disponibile nella man page
+di \func{sigaction}.
+
+Il resto della struttura è definito come \ctyp{union} ed i valori
eventualmente presenti dipendono dal segnale, così \macro{SIGCHLD} ed i
-segnali POSIX.1b\footnote{NdA trovare quale sono e completare l'informazione.}
-inviati tramite \func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi
-valori corrispondenti al processo che ha emesso il segnale, \macro{SIGILL},
-\macro{SIGFPE}, \macro{SIGSEGV} e \macro{SIGBUS} avvalorano \var{si\_addr} con
-l'indirizzo cui è avvenuto l'errore, \macro{SIGIO} (vedi
-\secref{sec:file_asyncronous_io}) e \macro{SIGPOLL} avvalorano \var{si\_fd}
-con il numero del file descriptor.
+segnali real-time (vedi \secref{sec:sig_real_time}) inviati tramite
+\func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi valori corrispondenti
+al processo che ha emesso il segnale, \macro{SIGILL}, \macro{SIGFPE},
+\macro{SIGSEGV} e \macro{SIGBUS} avvalorano \var{si\_addr} con l'indirizzo cui
+è avvenuto l'errore, \macro{SIGIO} (vedi \secref{sec:file_asyncronous_io})
+avvalora \var{si\_fd} con il numero del file descriptor e \var{si\_band} per i
+dati urgenti su un socket.
Benché sia possibile usare nello stesso programma sia \func{sigaction} che
\func{signal} occorre molta attenzione, in quanto le due funzioni possono
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-#include <unistd.h> /* unix standard library */
-#include <signal.h> /* POSIX signal library */
void alarm_hand(int);
unsigned int sleep(unsigned int seconds)
{
-/*
- * Variables definition
- */
struct sigaction new_action, old_action;
sigset_t old_mask, stop_mask, sleep_mask;
/* set the signal handler */
/* return remaining time */
return alarm(0);
}
-/*
- * Signal Handler for SIGALRM
- */
void alarm_hand(int sig)
{
return; /* just return to interrupt sigsuspend */
\var{sleep\_mask} per riattivare \macro{SIGALRM} all'esecuzione di
\func{sigsuspend}.
-In questo modo non sono più possibili race condition\index{race conditionx}
+In questo modo non sono più possibili race condition\index{race condition}
dato che \macro{SIGALRM} viene disabilitato con \func{sigprocmask} fino alla
chiamata di \func{sigsuspend}. Questo metodo è assolutamente generale e può
essere applicato a qualunque altra situazione in cui si deve attendere per un
segnale, i passi sono sempre i seguenti:
-\begin{enumerate}
+\begin{enumerate*}
\item Leggere la maschera dei segnali corrente e bloccare il segnale voluto
con \func{sigprocmask}.
\item Mandare il processo in attesa con \func{sigsuspend} abilitando la
ricezione del segnale voluto.
\item Ripristinare la maschera dei segnali originaria.
-\end{enumerate}
+\end{enumerate*}
Per quanto possa sembrare strano bloccare la ricezione di un segnale per poi
riabilitarla immediatamente dopo, in questo modo si evita il deadlock dovuto
all'arrivo del segnale prima dell'esecuzione di \func{sigsuspend}.
\secref{sec:proc_mem_layout}) solo durante l'esecuzione di un
manipolatore. L'uso di uno stack alternativo è del tutto trasparente ai
manipolatori, occorre però seguire una certa procedura:
-\begin{enumerate}
+\begin{enumerate*}
\item Allocare un'area di memoria di dimensione sufficiente da usare come
stack alternativo.
\item Usare la funzione \func{sigaltstack} per rendere noto al sistema
specificando il flag \macro{SA\_ONSTACK} (vedi \tabref{tab:sig_sa_flag}) per
dire al sistema di usare lo stack alternativo durante l'esecuzione del
manipolatore.
-\end{enumerate}
+\end{enumerate*}
In genere il primo passo viene effettuato allocando un'opportuna area di
memoria con \code{malloc}; in \file{signal.h} sono definite due costanti,
2.1(?).} in particolare sono stati superati tre limiti fondamentali dei
segnali classici:
\begin{description}
-\item[I segnali non sono accumulati] se più segnali vengono generati prima
- dell'esecuzione di un manipolatore questo sarà eseguito una sola volta, ed
- il processo non sarà in grado di accorgersi di quante volte l'evento che ha
- generato il segnale è accaduto.
-\item[I segnali non trasportano informazione] i segnali classici non prevedono
- prevedono altra informazione sull'evento che li ha generati che il loro
- numero.
-\item[I segnali non hanno un ordine di consegna] l'ordine in cui diversi
- segnali vengono consegnati è casuale e non prevedibile, e dipende dalla
- situazione in cui si trova il kernel al momento.
+\item[I segnali non sono accumulati]
+
+ se più segnali vengono generati prima dell'esecuzione di un manipolatore
+ questo sarà eseguito una sola volta, ed il processo non sarà in grado di
+ accorgersi di quante volte l'evento che ha generato il segnale è accaduto.
+\item[I segnali non trasportano informazione]
+
+ i segnali classici non prevedono prevedono altra informazione sull'evento
+ che li ha generati se non il fatto che sono stati emessi (tutta
+ l'informazione che il kernel associa ad un segnale è il suo numero).
+\item[I segnali non hanno un ordine di consegna]
+
+ l'ordine in cui diversi segnali vengono consegnati è casuale e non
+ prevedibile. Non è possibile stabilire una priorità per cui la reazione a
+ certi segnali ha la precedenza rispetto ad altri.
\end{description}
-Le nuove caratteristiche aggiunte a quelli che vengono chiamati
-\textsl{segnali real-time}, sono le seguenti:
+
+Per poter superare queste limitazioni lo standard ha introdotto delle nuove
+caratteristiche, che sono state associate ad una nuova classe di segnali, che
+vengono chiamati \textsl{segnali real-time}, in particolare:
\begin{itemize*}
-\item la creazione di una coda che permette di consegnare istanze multiple
- dello stesso segnale qualora esso venga inviato più volte prima
- dell'esecuzione del manipolatore.
-\item l'introduzione di una priorità nella consegna dei segnali (segnali a
- priorità più alta vengono consegnati prima).
-\item la possibilità di restituire dei dati al manipolatore, attraverso l'uso
- della struttura \type{siginfo\_t} e dei manipolatori di tipo
- \var{sa_sigaction}.
+\item i segnali sono inseriti in una coda che permette di consegnare istanze
+ multiple dello stesso segnale qualora esso venga inviato più volte prima
+ dell'esecuzione del manipolatore; si assicura così che il processo riceva un
+ segnale per ogni occorrenza dell'evento che lo genera.
+\item è stata introdotta una priorità nella consegna dei segnali: i segnali
+ vengono consegnati in ordine a seconda del loro valore, partendo da quelli
+ con un numero minore, che pertanto hanno una priorità maggiore.
+\item è stata introdotta la possibilità di restituire dei dati al
+ manipolatore, attraverso l'uso di un campo apposito nella struttura
+ \type{siginfo\_t} accessibile tramite manipolatori di tipo
+ \var{sa\_sigaction}.
\end{itemize*}
-Per non interferire con i segnali standard POSIX i nuovi segnali sono
-definiti, in \file{signal.h} a partire da un valore minimo \macro{SIGRTMIN}
-fino \macro{SIGRTMAX} ad un massimo di
+Queste nuove caratteristiche (eccetto l'ultima, che, come visto in
+\secref{sec:sig_sigaction}, è parzialmente disponibile anche con i segnali
+ordinari) si applicano solo ai nuovi segnali real-time; questi ultimi sono
+accessibili in un range di valori specificati dalle due macro \macro{SIGRTMIN}
+e \macro{SIGRTMAX},\footnote{in Linux di solito il primo valore è 32, ed il
+ secondo \code{\_NSIG-1}, che di norma è 63, per un totale di 32 segnali
+ disponibili, contro gli almeno 8 richiesti da POSIX.1b.} che specificano il
+numero minimo e massimo associato ad un segnale real-time.
+
+I segnali con un numero più basso hanno una priorità maggiore e vengono
+consegnati per primi, inoltre i segnali real-time non possono interrompere
+l'esecuzione di un manipolatore di un segnale a priorità più alta; la loro
+azione di default è quella di terminare il programma. I segnali ordinari
+hanno tutti la stessa priorità, che è più alta di quella di qualunque segnale
+real-time.
+
+Si tenga presente che questi nuovi segnali non sono associati a nessun evento
+sepcifico (a meno di non utilizzarli, come vedremo in
+\secref{sec:file_asyncronous_io}, per l'I/O asincrono) e devono essere inviati
+esplicitamente. Tutti i segnali real-time restituiscono al manipolatore, oltre
+ai campi \var{si\_pid} e \var{si\_uid} di \type{siginfo\_t} una struttura
+\type{sigval} (riportata in \figref{fig:sig_sigval}) in cui può essere
+restituito al processo un valore o un indirizzo, che costituisce il meccanismo
+con cui il segnale è in grado di inviare una ulteriore informazione al
+processo.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+union sigval {
+ int sival_int;
+ void *sival_ptr;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \type{sigval}, usata dai segnali real time per
+ restituire dati al manipolatore.}
+ \label{fig:sig_sigval}
+\end{figure}
+
+A causa di queste loro caratteristiche, la funzione \func{kill} non è adatta
+ad inviare un segnale real time, in quanto non è in grado di fornire alcun
+valore per \var{sigval}; per questo motivo lo standard ha previsto una nuova
+funzione, \func{sigqueue}, il cui prototipo è:
+\begin{prototype}{signal.h}
+ {int sigqueue(pid\_t pid, int signo, const union sigval value)}
+
+ Invia il segnale \param{signo} al processo \param{pid}, restituendo al
+ manipolatore il valore \param{value}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ errore, nel qual caso \var{errno} viene settata ai valori:
+ \begin{errlist}
+ \item[\macro{EAGAIN}] La coda è esarita, ci sono già \macro{SIGQUEUE\_MAX}
+ segnali in attesa si consegna.
+ \item[\macro{EPERM}] Non si hanno privilegi appropriati per inviare il
+ segnale al processo specificato.
+ \item[\macro{ESRCH}] Il processo \param{pid} non esiste.
+ \item[\macro{EINVAL}] Si è specificato un valore non valido per
+ \param{signo}.
+ \end{errlist}
+ ed inoltre \macro{ENOMEM}.}
+\end{prototype}
+
+Il comportamento della funzione è analogo a quello di \func{kill}, ed i
+privilegi occorrenti ad inviare il segnale ad un determinato processo sono gli
+stessi; un valore nullo di \func{signo} permette di verificare le condizioni
+di errore senza inviare nessun segnale.
+
+Se il segnale è bloccato la funzione ritorna immediatamente, se si è
+installato un manipolatore con \macro{SA\_SIGINFO} e ci sono risorse
+disponibili, vale a dire che c'è posto nella coda\footnote{la profondità della
+ coda è indicata dalla costante \macro{SIGQUEUE\_MAX}, una della tante
+ costanti di sistema definite dallo standard POSIX, che non abbiamo riportato
+ esplicitamente in \secref{sec:sys_limits}. Il suo valore minimo secondo lo
+ standard, \macro{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32.}, esso viene inserito
+e diventa pendente; una volta consegnato riporterà nel campo \var{si\_code} di
+\var{siginfo} il valore \macro{SI\_QUEUE} e il campo \var{si\_value} riceverà
+quanto inviato con \param{value}. Se invece si è installato un manipolatore
+nella forma classica il segnale sarà generato, ma in caso di emissioni
+multiple prima dell'esecuzione del manipolatore, sarà ricevuto una sola volta.