From: Simone Piccardi Date: Tue, 26 Mar 2002 23:16:05 +0000 (+0000) Subject: Aggiuno un altro esempio X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=e861c0f37f9eb16aed0f8bfbdb37afa04df1f685;p=gapil.git Aggiuno un altro esempio --- diff --git a/signal.tex b/signal.tex index fec20a7..bbfea4f 100644 --- a/signal.tex +++ b/signal.tex @@ -19,6 +19,7 @@ di generazione fino ad esaminare in dettaglio funzioni e le metodologie di gestione. + \section{Introduzione} \label{sec:sig_intro} @@ -1460,7 +1461,7 @@ della generazione di altri segnali dello stesso tipo. In questo caso normalmente i segnali vengono ``fusi'' insieme ed al processo ne viene recapitato soltanto uno. -Questo può essere un caso comune proprio con \texttt{SIGCHLD}, quando molti +Questo può essere un caso comune proprio con \macro{SIGCHLD}, quando molti processi figli terminano in rapida successione. Esso comunque si presenta tutte le volte che un segnale viene bloccato: per quanti siano i segnali emessi durante il periodo di blocco, una volta che esso viene rimosso ne sarà @@ -1480,6 +1481,7 @@ permette di evitare che essa si blocchi quando tutti gli stati di terminazione sono stati ricevuti. + \section{Gestione avanzata} \label{sec:sig_control} @@ -1490,7 +1492,9 @@ che i segnali possono generare e alla natura asincrona degli stessi. Affronteremo queste problematiche in questa sezione, partendo da un esempio che le evidenzi, per poi prendere in esame le varie funzioni che permettono di -risolvere i problemi più complessi connessi alla programmazione con i segnali. +risolvere i problemi più complessi connessi alla programmazione con i segnali, +fino a trattare le caratteristiche generali della gestione dei medesimi nella +casistica ordinaria. \subsection{Un esempio di problema} @@ -1502,6 +1506,13 @@ vista questo pu semplice versione di \func{sleep} potrebbe essere la seguente quella illustrata in \ref{fig:sig_sleep_wrong}. +In questo caso si salva il precedente manipolatore in (\texttt{\small 15--21}) +per poi chiamare in sequenza \func{alarm} per specificare l'attesa e +\func{pause} per fermare il programma. Al ritorno di pause, causato dal +ritorno del manipolatore (\texttt{\small 15--21}) si ripristina il +manipolatore (\texttt{\small 15--21}) restituendo l'eventuale tempo rimanente +(\texttt{\small 15--21}). + \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} @@ -1532,21 +1543,70 @@ void alarm_hand(int sig) { \end{lstlisting} \end{minipage} \normalsize - \caption{Una implementazione sbagliata di \func{sleep}.} + \caption{Una implementazione pericolosamente sbagliata di \func{sleep}.} \label{fig:sig_sleep_wrong} \end{figure} -Ma questa funzione, a parte il non gestire il caso in cui si è avuta una +Ma questo codice, a parte il non gestire il caso in cui si è avuta una precedente chiamata a \func{alarm}, presenta una pericolosa race condition. Infatti se il processo viene interrotto fra la chiamata di \func{alarm} e -\func{pause} può capitare (nel caso il sistema sia molto carico) che +\func{pause} può capitare (ad esempio se il sistema è molto carico) che quest'ultima possa essere eseguita dopo l'arrivo di \macro{SIGALRM}. In questo caso ci si troverebbe di fronte ad un deadlock, in cui \func{pause} non -verrebbe mai interrotta (se non in caso di un altro segnale). +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 modo da sfruttare lo stato di uscita di +quest'ultima per evitare la chiamata a \func{pause}, con un codice del tipo: + +\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 modo all'uscita dal manipolatore si eviterà comunque la chiamata di +\func{pause}, dato che in questo caso il valore di uscita di \func{setjmp} è +uno ed il condizionale in (\texttt{\small 15--21}) viene evitato. -Come abbiamo accennato in \secref{sec:proc_atom_oper} quando si ha a che fare -con i segnali +Ma anche questa implementazione comporta dei problemi; in questo caso infatti +non viene gestita correttamente l'interazione con 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.