+\subsection{Alcune problematiche aperte}
+\label{sec:sig_example}
+
+Come accennato in \secref{sec:sig_pause_sleep} è possibile implementare
+\func{sleep} a partire da dall'uso di \func{pause} e \func{alarm}. A prima
+vista questo può sembrare di implementazione immediata; ad esempio una
+semplice versione di \func{sleep} potrebbe essere quella illustrata in
+\figref{fig:sig_sleep_wrong}.
+
+
+Dato che è nostra intenzione utilizzare \macro{SIGALARM} il primo passo della
+nostra implementazione di sarà quello di installare il relativo manipolatore
+salvando il precedente (\texttt{\small 4-7}). Si effettuerà poi una chiamata
+ad \func{alarm} per specificare il tempo d'attesa per l'invio del segnale a
+cui segue la chiamata a \func{pause} per fermare il programma (\texttt{\small
+ 8-9}) fino alla sua ricezione. Al ritorno di \func{pause}, causato dal
+ritorno del manipolatore (\texttt{\small 15-23}), si ripristina il
+manipolatore originario (\texttt{\small 10-11}) restituendo l'eventuale tempo
+rimanente (\texttt{\small 12-13}) che potrà essere diverso da zero qualora
+l'interruzione di \func{pause} venisse causata da un altro segnale.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+unsigned int sleep(unsigned int seconds)
+{
+ signandler_t prev_handler;
+ if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
+ printf("Cannot set handler for alarm\n");
+ exit(1);
+ }
+ alarm(second);
+ pause();
+ /* restore previous signal handler */
+ signal(SIGALRM, prev_handler);
+ /* remove alarm, return remaining time */
+ return alarm(0);
+}
+void alarm_hand(int sig)
+{
+ /* check if the signal is the right one */
+ if (sig != SIGALRM) { /* if not exit with error */
+ printf("Something wrong, handler for SIGALRM\n");
+ exit(1);
+ } else { /* do nothing, just interrupt pause */
+ return;
+ }
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Una implementazione pericolosa di \func{sleep}.}
+ \label{fig:sig_sleep_wrong}
+\end{figure}
+
+Questo codice però, a parte il non gestire il caso in cui si è avuta una
+precedente chiamata a \func{alarm} (che si è tralasciato per brevità),
+presenta una pericolosa race condition. Infatti se il processo viene
+interrotto fra la chiamata di \func{alarm} e \func{pause} può capitare (ad
+esempio se il sistema è molto carico) che il tempo di attesa scada prima
+dell'esecuzione quest'ultima, cosicchè essa sarebbe eseguita dopo l'arrivo di
+\macro{SIGALRM}. In questo caso ci si troverebbe di fronte ad un deadlock, in
+quanto \func{pause} non verrebbe mai più interrotta (se non in caso di un
+altro segnale).
+
+Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
+SVr2) usando la funzione \func{longjump} (vedi \secref{sec:proc_longjmp}) per
+uscire dal manipolatore; in questo modo, con una condizione sullo stato di
+uscita di quest'ultima, si può evitare la chiamata a \func{pause}, usando un
+codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+static jmp_buff alarm_return;
+unsigned int sleep(unsigned int seconds)
+{
+ signandler_t prev_handler;
+ if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
+ printf("Cannot set handler for alarm\n");
+ exit(1);
+ }
+ if (setjmp(alarm_return) == 0) { /* if not returning from handler */
+ alarm(second); /* call alarm */
+ pause(); /* then wait */
+ }
+ /* restore previous signal handler */
+ signal(SIGALRM, prev_handler);
+ /* remove alarm, return remaining time */
+ return alarm(0);
+}
+void alarm_hand(int sig)
+{
+ /* check if the signal is the right one */
+ if (sig != SIGALRM) { /* if not exit with error */
+ printf("Something wrong, handler for SIGALRM\n");
+ exit(1);
+ } else { /* return in main after the call to pause */
+ longjump(alarm_return, 1);
+ }
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Una implementazione ancora malfunzionante di \func{sleep}.}
+ \label{fig:sig_sleep_incomplete}
+\end{figure}
+
+In questo caso il manipolatore (\texttt{\small 18-26}) non ritorna come in
+\figref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) per
+rientrare nel corpo principale del programma; dato che in questo caso il
+valore di uscita di \func{setjmp} è 1 grazie alla condizione in
+(\texttt{\small 9-12}) si evita comunque che \func{pause} sia chiamata a
+vuoto.
+
+Ma anche questa implementazione comporta dei problemi; in questo caso infatti
+non viene gestita correttamente l'interazione con gli altri segnali; se
+infatti il segnale di allarme interrompe un altro manipolatore, in questo caso
+l'esecuzione non riprenderà nel manipolatore in questione, ma nel ciclo
+principale, interrompendone inopportunamente l'esecuzione. Lo stesso tipo di
+problemi si presenterebbero se si volesse usare \func{alarm} per stabilire un
+timeout su una qualunque system call bloccante.
+
+Un secondo esempio è quello in cui si usa il segnale per notificare una
+quelche forma di evento; in genere quello che si fa in questo caso è settare
+nel manipolatore un opportuno flag da controllare nel corpo principale del
+programma (con un codice del tipo di quello riportato in
+\secref{fig:sig_event_wrong}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+sig_atomic_t flag;
+int main()
+{
+ flag = 0;
+ ...
+ if (flag) { /* test if signal occurred */
+ flag = 0; /* reset flag */
+ do_response(); /* do things */
+ } else {
+ do_other(); /* do other things */
+ }
+ ...
+}
+void alarm_hand(int sig)
+{
+ /* set the flag
+ flag = 1;
+ return;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Un esempio non funzionante del codice per il controllo di un
+ evento generato da un segnale.}
+ \label{fig:sig_event_wrong}
+\end{figure}
+
+La logica è quella di far settare al manipolatore (\texttt{\small 14-19}) una
+variabile globale preventivamente inizializzata nel programma principale, il
+quale potrà determinare, osservandone il contenuto, l'occorrenza o meno del
+segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}).
+
+Questo è il tipico esempio di caso, già citato in \secref{sec:proc_race_cond},
+in cui si genera una 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 della semplice interfaccia dei primi sistemi Unix,
+che permettano di gestire tutti i possibili aspetti con cui un processo deve
+reagire alla ricezione di un segnale.
+
+
+
+\subsection{I \textit{signal set}}
+\label{sec:sig_sigset}
+
+Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali
+dei primi Unix, nate con la semantica inaffidabile, hanno dei limiti non
+superabili; in particolare non è prevista nessuna funzione che permetta di
+gestire gestire il blocco dei segnali o di verificare lo stato dei segnali
+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 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.
+
+In genere un \textit{signal set} è rappresentato da un intero di dimensione
+opportuna, di solito si pari al numero di bit dell'architettura della
+macchina\footnote{nel caso dei PC questo comporta un massimo di 32 segnali
+ distinti, dato che in Linux questi sono sufficienti non c'è necessità di
+ nessuna struttura più complicata.}, ciascun bit del quale è associato ad uno
+specifico segnale; in questo modo è di solito possibile implementare le
+operazioni direttamente con istruzioni elementari del processore; lo standard
+POSIX.1 definisce cinque funzioni per la manipolazione dei \textit{signal set},
+\func{sigemptyset}, \func{sigfillset}, \func{sigaddset}, \func{sigdelset} e
+\func{sigismember}, i cui prototipi sono:
+\begin{functions}
+ \headdecl{signal.h}
+
+ \funcdecl{int sigemptyset(sigset\_t *set)} Inizializza un \textit{signal set}
+ vuoto.
+
+ \funcdecl{int sigfillset(sigset\_t *set)} Inizializza un \textit{signal set}
+ pieno (con tutti i segnali).
+
+ \funcdecl{int sigaddset(sigset\_t *set, int signum)} Aggiunge il segnale
+ \param{signum} al \textit{signal set} \param{set}.
+
+ \funcdecl{int sigdelset(sigset\_t *set, int signum)} Toglie il segnale
+ \param{signum} dal \textit{signal set} \param{set}.
+
+ \funcdecl{int sigismember(const sigset\_t *set, int signum)} Controlla se il
+ segnale \param{signum} è nel \textit{signal set} \param{set}
+
+ \bodydesc{Le prime quattro funzioni ritornano 0 in caso di successo, mentre
+ \func{sigismember} ritorna 1 se \param{signum} è in \param{set} e 0
+ altrimenti. In caso di errore tutte ritornano -1, con \var{errno} settata a
+ \macro{EINVAL} (il solo errore possibile è che \param{signum} non sia un
+ segnale valido).}
+\end{functions}
+
+Dato che in generale non si può fare conto sulle caratteristiche di una
+implementazione (non è detto che si disponga di un numero di bit sufficienti
+per mettere tutti i segnali in un intero, o in \type{sigset\_t} possono essere
+immagazzinate ulteriori informazioni) tutte le operazioni devono essere
+comunque eseguite attraverso queste funzioni.