From: Simone Piccardi Date: Mon, 25 Jun 2001 20:02:55 +0000 (+0000) Subject: Aggiunte alle semantiche X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=099f22175fea906f225c452da0d6419f08a146eb;p=gapil.git Aggiunte alle semantiche --- diff --git a/gapil.tex b/gapil.tex index 2564ee7..a8b017b 100644 --- a/gapil.tex +++ b/gapil.tex @@ -1,4 +1,4 @@ -%% +%% %% GaPiL : Guida alla Programmazione in Linux %% %% S. Piccardi Feb. 2001 diff --git a/signal.tex b/signal.tex index d819acd..4fb155d 100644 --- a/signal.tex +++ b/signal.tex @@ -28,14 +28,14 @@ segnale sono vari; un breve elenco di possibile cause essere eseguita. \item una richiesta dell'utente di terminare o fermare il programma. In genere si realizza attraverso un segnale mandato dalla shell in corrispondenza - della pressione di tasti come 'ctrl-c' o 'ctrl-z'. + della pressione di tasti del terminale come 'ctrl-c' o 'ctrl-z'. \item l'esecuzione di una \texttt{kill} o di una \texttt{raise} da parte del processo stesso o di un'altro (solo nel caso della \texttt{kill}). \end{itemize} Ciascuno di questi eventi (tranne gli ultimi due che sono controllati -dall'utente) comporta da parte del kernel la generazione un particolare tipo -di segnale. +dall'utente) comporta l'intervento diretto da parte del kernel che causa la +generazione un particolare tipo di segnale. \subsection{Le modalità di funzionamento} @@ -44,41 +44,97 @@ di segnale. Quando un processo riceve un segnale il kernel esegue una apposita routine di gestione (il cosiddetto \textit{signal handler}) che può essere specificata dall'utente. Negli anni il comportamento del sistema in risposta ai segnali è -stato modificato in vari modi nelle differenti implementazioni di unix. -Attualmente si possono individuare due tipologie fondamentali di comportamento -dei segnali (dette semantiche) che vengono chiamate rispettivamente -\textit{reliable} e \textit{unreliable}. +stato modificato in vari modi nelle differenti implementazioni di unix. Si +possono individuare due tipologie fondamentali di comportamento dei segnali +(dette semantiche) che vengono chiamate rispettivamente \textit{reliable} e +\textit{unreliable}. -Nella semantica \textit{unreliable} la routine di gestione del segnale -specificata dall'utente non resta installata una volta chiamata; è perciò a -carico dell'utente stesso ripetere l'installazione all'interno della routine -di gestione stessa in tutti i casi in cui si vuole che il signal handler -esterno resti attivo. +Nella semantica \textit{unreliable} (quella implementata dalle prime versioni +di unix) la routine di gestione del segnale specificata dall'utente non resta +installata una volta chiamata; è perciò a carico dell'utente stesso ripetere +l'installazione all'interno della routine di gestione stessa in tutti i casi +in cui si vuole che il signal handler esterno resti attivo. Per questo motivo è possibile una race-condition in cui un secondo segnale arriva prima che il manipolatore abbia eseguito la re-installazione di se -stesso, nel qual caso il segnale può essere perso o causare il comportamento +stesso. In questo caso il segnale può essere perso o causare il comportamento originale assegnato al segnale (in genere la terminazione del processo). -Questa è la ragione per cui detti segnali sono chiamati \textit{inaffidabili}, -in quanto la ricezione del segnale e la reinstallazione del suo manipolatore -non sono operazioni atomiche. -Nel caso di implementazione inaffidabile le chiamate di sistema non -sono fatte ripartire automaticamente quando sono interrotte da un segnale, per -questo il programma deve controllare lo stato di uscita della chiamata al -sistema e riperterla nel caso l'errore riportato da \texttt{errno} sia -\texttt{EINTR}. +Questa è la ragione per cui l'implementazione dei segnali secondo questa +semantica viene chiamata \textit{inaffidabile}, in quanto la ricezione del +segnale e la reinstallazione del suo manipolatore non sono operazioni +atomiche. + +Un'altro problema è che in questa semantica è che non esiste un modo per +bloccare i segnali quando non si vuole che arrivino; i processi possono +ignorare il segnale, ma non è possibile istruire il sistema a non fare nulla +in occasione di un segnale, pur mantenendo memoria del fatto che è avvenuto. + +Un caso classico, riportato da Stevens, in cui si incontra questo problema, è +quello in cui si usa il manipolatore per settare un flag che riporta al +processo l'occorrenza del segnale, se si considera il seguente segmento di +codice: +\begin{lstlisting} +int signal_flag = 0; +main () +{ + int sig_handler(); /* handler function */ + ... + signal(SIGINT, sig_handler); /* establish handler */ + ... + while(signal_flag == 0) /* while flag is zero */ + pause(); /* go to sleep */ + ... +} +int sig_handler() +{ + signal(SIGINT, sig_handler); /* restablish handler */ + signal_flag = 1; /* set flag */ +} +\end{lstlisting} + + +% non supporta l'ultima delle due ma vale la pena parlarne +% dato che è stata la prima ad essere stata implementata (e se ne trovano +% conseguenze in alcuni programmi e funzioni di libreria) ed illustra bene +% alcune delle caratteristiche dei segnali. + + +% Un'altra caratteristica della implementazione inaffidabile è che le chiamate +% di sistema non sono fatte ripartire automaticamente quando sono interrotte da +% un segnale, per questo un programma deve controllare lo stato di uscita della +% chiamata al sistema e riperterla nel caso l'errore riportato da \texttt{errno} +% sia \texttt{EINTR}. Inoltre in questo caso non esiste una modalità semplice per ottenere una operazione di pausa atomica (cioè mandare in sleep un processo fino all'arrivo di un segnale), dato che ci sono casi in cui un segnale può arrivare quando il programma non è in grado di accorgersene. -In caso di segnali \textit{reliable} invece il signal handler resta installato -quando viene chiamato e i problemi precedenti sono evitati. Inoltre alcune -chiamate di sistema possono essere fatte ripartire automaticamente e si può -ottenere un'operazione di pausa atomica (usando la funzione POSIX -\texttt{sigsuspend}). +Nella semantica \textit{reliable} (quella utilizzata da Linux e da ogni Unix +moderno) invece il signal handler una volta installato resta attivo e non si +hanno tutti i problemi precedenti. In questa semantica i segnali vengono +\textsl{generati} dal kernel per un processo all'occorrenza dell'evento che +causa il segnale. In genere questo viene fatto dal kernel settanto un flag +nella process table del processo. + +Si dice che il segnale viene \textsl{consegnato} al processo (dall'inglese +\textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre +per tutto il tempo che passa fra la generazione del segnale e la sua consegna +esso è detto \textsl{pendente}. In genere questa procedura viene effettuata +dal kernel quando, riprendendo l'esecuzione del processo in questione, verifica +la presenza del flag del segnale nella process table. + +In questa semantica un processo può bloccare i segnali + + +% Torneremo su +% questo più avanti in \secref{sec:sig_linux_sematic}. + +% Inoltre alcune +% chiamate di sistema possono essere fatte ripartire automaticamente e si può +% ottenere un'operazione di pausa atomica (usando la funzione POSIX +% \texttt{sigsuspend}). \subsubsection{Tipi di segnali} @@ -198,7 +254,6 @@ che i numeri dei segnali sono allocati progressivamente, essa corrisponde anche al successivo del valore numerico assegnato all'ultimo segnale definito. In \ntab\ si è riportato l'elenco completo dei segnali definiti in Linux (estratto dalle man page), comparati con quelli definiti in vari standard. - \begin{table}[htb] \centering \begin{tabular}[c]{|l|c|c|c||c|l|} @@ -249,8 +304,17 @@ In \ntab\ si \caption{Lista dei segnali in Linux} \label{tab:sig_signal_list} \end{table} -in \curtab\ si sono riportate anche le caratteristiche di ciascun segnale, -indicate con una lettera nel campo azione, la cui legenda è: +in \curtab\ si sono riportate le azioni di default di ciascun segnale +(riassunte con delle lettere, la cui legenda completa è in \ntab), quando +nessun manipolatore è installato un segnale può essere ignorato o causare la +terminazione del processo. + +In alcuni casi alla terminazione del processo è associata la creazione di un +file (posto nella directory corrente del processo e chiamato \file{core}) su +cui viene salvata un'immagine della memoria del processo (il cosiddetto +\textit{core dump}), che può essere usata da un debugger per esaminare lo +stato dello stack e delle variabili al momento della ricezione del segnale. + \begin{table}[htb] \centering \begin{tabular}[c]{c p{6cm}} @@ -267,9 +331,7 @@ indicate con una lettera nel campo azione, la cui legenda \label{tab:sig_action_leg} \end{table} la descrizione dettagliata del significato dei vari segnali, raggruppati per -tipologia, è a seguire; una descrizione dettagliata del significato delle -varie azioni si trova invece in \secred{sec:sig_handlers}. - +tipologia, è a seguire. \subsubsection{Segnali di errore di programma} \label{sec:sig_prog_error} @@ -370,9 +432,8 @@ segnali sono: Questi segnali sono generati dalla scadenza di un temporizzatore. Il loro comportamento di default è quello di causare la terminazione del programma, ma -nessun default ha una utlità avrebbe una utilità particolare, in quanto l'uso -di questi segnali presuppone quasi sempre la necessità di un -manipolatore. Questi segnali sono: +con questi segnali la scelta di default è irrilevante, in quanto il loro uso +presuppone sempre la necessità di un manipolatore. Questi segnali sono: \begin{description} \item \texttt{SIGALRM} \item \texttt{SIGVTALRM} @@ -461,14 +522,18 @@ essere controllata all'interno del flusso di esecuzione di quest'ultimo, ma tutto quello che si potrà fare è di specificare (al kernel, che li genera) quale azione andrà intrapresa quando essi si verificano. -In questa sezione vedremo allora come si gestiscono i segnali, partendo dalla -descrizione di cosa fanno le azioni di default citate in precedenza, per poi -esaminare le funzioni usate per personalizzare la gestione dei segnali, -analizzando tutte le problematiche relative alla gestione di eventi asincroni -di questo tipo. +In questa sezione vedremo allora come si gestiscono i segnali, esaminando le +funzioni che si usano per effettuare la gestione dei segnali ed analizzando le +problematiche relative alla gestione di eventi asincroni di questo tipo. + + +\subsection{La semantica dei segnali in Linux} +\label{sec:sig_linux_semantic} + + +\subsection{La funzione \func{signal}} +\label{sec:sig_signal} -\subsection{Le azioni di default} -\label{sec:sig_default_acttion}