X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=5572fd4410886502429efef7316b4c1dd796f5de;hp=09f8325543a3370c5247a3f9877952a6502e02e6;hb=c68c98c80f516ecefd08f227f54fc81fb27a7872;hpb=2c682ba44f85eb183ddf75760b38bf048f89de53 diff --git a/signal.tex b/signal.tex index 09f8325..5572fd4 100644 --- a/signal.tex +++ b/signal.tex @@ -16,7 +16,7 @@ In questo capitolo esamineremo i vari aspetti della gestione dei segnali, partendo da una introduzione relativa ai concetti base con cui essi vengono realizzati, per poi affrontarne la classificazione a secondo di uso e modalità di generazione fino ad esaminare in dettaglio funzioni e le metodologie di -gestione. +gestione. \section{Introduzione} @@ -120,8 +120,8 @@ int sig_handler() Questa è la ragione per cui l'implementazione dei segnali secondo questa semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del segnale e la reinstallazione del suo manipolatore non sono operazioni -atomiche, e sono sempre possibili delle race condition (sull'argomento vedi -quanto detto in \secref{sec:proc_multi_prog}). +atomiche, e sono sempre possibili delle race condition\index{race condition} +(sull'argomento vedi quanto detto in \secref{sec:proc_multi_prog}). Un'altro problema è che in questa semantica non esiste un modo per bloccare i segnali quando non si vuole che arrivino; i processi possono ignorare il @@ -242,7 +242,8 @@ Un programma pu \secref{sec:sig_sigaction}). Se si è installato un manipolatore sarà quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema farà si che mentre viene eseguito il manipolatore di un segnale, quest'ultimo -venga automaticamente bloccato (così si possono evitare race condition). +venga automaticamente bloccato (così si possono evitare race +condition\index{race condition}). Nel caso non sia stata specificata un'azione, viene utilizzata l'azione standard che (come vedremo in \secref{sec:sig_standard}) è propria di ciascun @@ -411,9 +412,9 @@ tipologia, verr \label{sec:sig_prog_error} Questi segnali sono generati quando il sistema, o in certi casi direttamente -l'hardware (come per i page fault non validi) rileva un qualche errore -insanabile nel programma in esecuzione. In generale la generazione di questi -segnali significa che il programma ha dei gravi problemi (ad esempio ha +l'hardware (come per i \textit{page fault} non validi) rileva un qualche +errore insanabile nel programma in esecuzione. In generale la generazione di +questi segnali significa che il programma ha dei gravi problemi (ad esempio ha dereferenziato un puntatore non valido o ha eseguito una operazione aritmetica proibita) e l'esecuzione non può essere proseguita. @@ -662,11 +663,11 @@ segnali sono: situazione precedente. \item[\macro{SIGXCPU}] Sta per \textit{CPU time limit exceeded}. Questo segnale è generato quando un processo eccede il limite impostato per il - tempo di CPU disponibile, vedi \secref{sec:sys_xxx}. + tempo di CPU disponibile, vedi \secref{sec:sys_resource_limit}. \item[\macro{SIGXFSZ}] Sta per \textit{File size limit exceeded}. Questo segnale è generato quando un processo tenta di estendere un file oltre le dimensioni specificate dal limite impostato per le dimensioni massime di un - file, vedi \secref{sec:sys_xxx}. + file, vedi \secref{sec:sys_resource_limit}. \end{basedescript} @@ -714,7 +715,7 @@ di \func{strsignal}. Nel caso si debba mantenere traccia del messaggio sar necessario copiarlo. La seconda funzione deriva da BSD ed è analoga alla funzione \func{perror} -descritta in \secref{sec:sys_strerror}; il suo prototipo è: +descritta sempre in \secref{sec:sys_strerror}; il suo prototipo è: \begin{prototype}{signal.h}{void psignal(int sig, const char *s)} Stampa sullo standard error un messaggio costituito dalla stringa \param{s}, seguita da due punti ed una descrizione del segnale indicato da \param{sig}. @@ -750,7 +751,7 @@ processo alla loro occorrenza. \subsection{Il comportamento generale del sistema.} - \label{sec:sig_gen_beha} +\label{sec:sig_gen_beha} Abbiamo già trattato in \secref{sec:sig_intro} le modalità con cui il sistema gestisce l'interazione fra segnali e processi, ci resta da esaminare però il @@ -778,28 +779,29 @@ manipolatore; viene mantenuto invece ogni eventuale settaggio dell'azione a programmi eseguiti in background, che altrimenti sarebbero interrotti da una successiva pressione di \texttt{C-c} o \texttt{C-y}. -Per quanto riguarda tutte le altre system call esse vengono tradizionalmente -classificate, proprio in base al loro comportamento nei confronti dei segnali, -in \textsl{lente} (\textit{slow}) e \textsl{veloci} (\textit{fast}). La gran -parte appartiene a quest'ultima categoria che non è influenzata dall'arrivo di -un segnale. In tal caso un eventuale manipolatore viene sempre eseguito dopo -che la system call è stata completata. Esse sono dette \textsl{veloci} proprio -in quanto la loro esecuzione è sostanzialmente immediata e attendere per -eseguire un manipolatore non comporta nessun inconveniente. - -Esistono però dei casi in cui questo non è possibile perché renderebbe -impossibile una risposta pronta al segnale. In generale questo avviene tutte -le volte che si ha a che fare con system call che possono bloccarsi -indefinitamente, (quelle che, per questo, vengono chiamate \textsl{lente}). Un -elenco dei casi in cui si presenta questa situazione è il seguente: +Per quanto riguarda il comportamento di tutte le altre system call si danno +sostanzialmente due casi, a seconda che esse siano \textsl{lente} +(\textit{slow}) o \textsl{veloci} (\textit{fast}). La gran parte di esse +appartiene a quest'ultima categoria, che non è influenzata dall'arrivo di un +segnale. Esse sono dette \textsl{veloci} in quanto la loro esecuzione è +sostanzialmente immediata; la risposta al segnale viene sempre data dopo che +la system call è stata completata, in quanto attendere per eseguire un +manipolatore non comporta nessun inconveniente. + +In alcuni casi però alcune system call (che per questo motivo vengono chiamate +\textsl{lente}) possono bloccarsi indefinitamente. In questo caso non si può +attendere la conclusione della sistem call, perché questo renderebbe +impossibile una risposta pronta al segnale, per cui il manipolatore viene +eseguito prima che la system call sia ritornata. Un elenco dei casi in cui si +presenta questa situazione è il seguente: \begin{itemize} -\item lettura da file che possono bloccarsi in attesa di dati non ancora - presenti (come per certi file di dispositivo, la rete o le pipe). -\item scrittura sugli stessi file, nel caso in cui dati non possano essere +\item la lettura da file che possono bloccarsi in attesa di dati non ancora + presenti (come per certi file di dispositivo, i socket o le pipe). +\item la scrittura sugli stessi file, nel caso in cui dati non possano essere accettati immediatamente. -\item apertura di un file di dispositivo che richiede operazioni non immediate - per una una risposta. -\item operazioni eseguite con \func{ioctl} che non è detto possano essere +\item l'apertura di un file di dispositivo che richiede operazioni non + immediate per una una risposta. +\item le operazioni eseguite con \func{ioctl} che non è detto possano essere eseguite immediatamente. \item le funzioni di intercomunicazione che si bloccano in attesa di risposte da altri processi. @@ -1120,7 +1122,7 @@ illustrati in precedenza usare; i possibili valori sono riportati in Il valore della struttura specificata \param{value} viene usato per settare il timer, se il puntatore \param{ovalue} non è nullo il precedente valore viene salvato qui. I valori dei timer devono essere indicati attraverso una -struttura \var{itimerval}, definita in \figref{fig:file_stat_struct}. +struttura \type{itimerval}, definita in \figref{fig:file_stat_struct}. La struttura è composta da due membri, il primo, \var{it\_interval} definisce il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla @@ -1144,7 +1146,7 @@ struct itimerval \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \var{itimerval}, che definisce i valori dei timer di + \caption{La struttura \type{itimerval}, che definisce i valori dei timer di sistema.} \label{fig:sig_itimerval} \end{figure} @@ -1400,7 +1402,7 @@ la creazione di zombie. #include #include "macro.h" -void Hand_CHLD(int sig) +void sigchld_hand(int sig) { int errno_save; int status; @@ -1471,8 +1473,9 @@ tutti gli stati di terminazione sono stati ricevuti. Le funzioni esaminate finora fanno riferimento ad alle modalità più elementari della gestione dei segnali; non si sono pertanto ancora prese in -considerazione le tematiche più complesse, collegate alle varie race condition -che i segnali possono generare e alla natura asincrona degli stessi. +considerazione le tematiche più complesse, collegate alle varie race +condition\index{race condition} 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 @@ -1539,13 +1542,13 @@ unsigned int sleep(unsigned int seconds) 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). +presenta una pericolosa race condition\index{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{longjmp} (vedi \secref{sec:proc_longjmp}) per @@ -1649,10 +1652,10 @@ quale potr 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. +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 @@ -1794,16 +1797,6 @@ struct sigaction \label{fig:sig_sigaction} \end{figure} -Come si può notare da quanto riportato in \figref{fig:sig_sigaction} in Linux -\func{sigaction} permette di specificare il manipolatore in due forme diverse, -indicate dai campi \var{sa\_handler} e \var{sa\_sigaction}; esse devono essere -usate in maniera alternativa (in certe implementazioni questi vengono -specificati come \ctyp{union}): la prima è quella classica usata anche con -\func{signal}, la seconda permette invece di usare un manipolatore in grado di -ricevere informazioni più dettagliate dal sistema (ad esempio il tipo di -errore in caso di \macro{SIGFPE}), attraverso dei parametri aggiuntivi; per i -dettagli si consulti la man page di \func{sigaction}). - Il campo \var{sa\_mask} serve ad indicare l'insieme dei segnali che devono essere bloccati durante l'esecuzione del manipolatore, ad essi viene comunque sempre aggiunto il segnale che ne ha causato la chiamata, a meno che non si @@ -1860,6 +1853,68 @@ in \tabref{tab:sig_sa_flag}. \label{tab:sig_sa_flag} \end{table} +Come si può notare in \figref{fig:sig_sigaction} \func{sigaction} +permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ma in + Linux è stata aggiunta a partire dai kernel della serie 2.2.x. 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 questi vengono addirittura definiti come \ctyp{union}): la +prima è quella classica usata anche con \func{signal}, la seconda permette +invece di usare un manipolatore in grado di ricevere informazioni più +dettagliate dal sistema, attraverso la struttura \type{siginfo\_t}, riportata +in \figref{fig:sig_siginfo_t}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +siginfo_t { + int si_signo; /* Signal number */ + int si_errno; /* An errno value */ + int si_code; /* Signal code */ + pid_t si_pid; /* Sending process ID */ + uid_t si_uid; /* Real user ID of sending process */ + int si_status; /* Exit value or signal */ + clock_t si_utime; /* User time consumed */ + clock_t si_stime; /* System time consumed */ + sigval_t si_value; /* Signal value */ + int si_int; /* POSIX.1b signal */ + void * si_ptr; /* POSIX.1b signal */ + void * si_addr; /* Memory location which caused fault */ + int si_band; /* Band event */ + int si_fd; /* File descriptor */ +} + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \type{siginfo\_t}.} + \label{fig:sig_siginfo_t} +\end{figure} + +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 +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. + Benché sia possibile usare nello stesso programma sia \func{sigaction} che \func{signal} occorre molta attenzione, in quanto le due funzioni possono interagire in maniera anomala. Infatti l'azione specificata con @@ -1873,16 +1928,9 @@ Per questo ripristinare correttamente un manipolatore precedente, anche se questo è stato installato con \func{signal}. In generale poi non è il caso di usare il valore di ritorno di \func{signal} come campo \var{sa\_handler}, o viceversa, dato -che in certi sistemi questi possono essere diversi. In generale dunque, a meno -che non si sia vincolati allo standard ISO C, è sempre il caso di evitare -l'uso di \func{signal} a favore di \func{sigaction}. - -Per questo motivo si è provveduto, per mantenere un'interfaccia semplificata -che abbia le stesse caratteristiche di \func{signal}, a definire una funzione -equivalente attraverso \func{sigaction}; la funzione è \code{Signal}, e si -trova definita come \code{inline} nel file \file{wrapper.h} (nei sorgenti -allegati), riportata in \figref{fig:sig_Signal_code}. La riutilizzeremo spesso -in seguito. +che in certi sistemi questi possono essere diversi. In definitiva dunque, a +meno che non si sia vincolati all'aderenza stretta allo standard ISO C, è +sempre il caso di evitare l'uso di \func{signal} a favore di \func{sigaction}. \begin{figure}[!htb] \footnotesize \centering @@ -1914,6 +1962,13 @@ inline SigFunc * Signal(int signo, SigFunc *func) \label{fig:sig_Signal_code} \end{figure} +Per questo motivo si è provveduto, per mantenere un'interfaccia semplificata +che abbia le stesse caratteristiche di \func{signal}, a definire una funzione +equivalente attraverso \func{sigaction}; la funzione è \code{Signal}, e si +trova definita come \code{inline} nel file \file{wrapper.h} (nei sorgenti +allegati), riportata in \figref{fig:sig_Signal_code}. La riutilizzeremo spesso +in seguito. + \subsection{La gestione della \textsl{maschera dei segnali} o \textit{signal mask}} \label{sec:sig_sigmask} @@ -1995,15 +2050,15 @@ occorre ricordare che qualunque modifica alla maschera dei segnali viene perduta alla conclusione del terminatore. Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte -dei casi di race condition restano aperte alcune possibilità legate all'uso di -\func{pause}; il caso è simile a quello del problema illustrato nell'esempio -di \secref{fig:sig_sleep_incomplete}, e cioè la possibilità che il processo -riceva il segnale che si intende usare per uscire dallo stato di attesa -invocato con \func{pause} immediatamente prima dell'esecuzione di -quest'ultima. Per poter effettuare atomicamente la modifica della maschera dei -segnali (di solito attivandone uno specifico) insieme alla sospensione del -processo lo standard POSIX ha previsto la funzione \func{sigsuspend}, il cui -prototipo è: +dei casi di race condition\index{race condition} restano aperte alcune +possibilità legate all'uso di \func{pause}; il caso è simile a quello del +problema illustrato nell'esempio di \secref{fig:sig_sleep_incomplete}, e cioè +la possibilità che il processo riceva il segnale che si intende usare per +uscire dallo stato di attesa invocato con \func{pause} immediatamente prima +dell'esecuzione di quest'ultima. Per poter effettuare atomicamente la modifica +della maschera dei segnali (di solito attivandone uno specifico) insieme alla +sospensione del processo lo standard POSIX ha previsto la funzione +\func{sigsuspend}, il cui prototipo è: \begin{prototype}{signal.h} {int sigsuspend(const sigset\_t *mask)} @@ -2093,10 +2148,10 @@ fine (\texttt{\small 27}), e al contempo si prepara la maschera dei segnali \var{sleep\_mask} per riattivare \macro{SIGALRM} all'esecuzione di \func{sigsuspend}. -In questo modo non sono più possibili 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 +In questo modo non sono più possibili race condition\index{race conditionx} +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} \item Leggere la maschera dei segnali corrente e bloccare il segnale voluto @@ -2278,26 +2333,6 @@ ripristinata in un successivo \func{siglongjmp}; quest'ultima funzione, a parte l'uso di \type{sigjmp\_buf} per \param{env}, è assolutamente identica a \func{longjmp}. -\begin{prototype}{signal.h} -{int sigaltstack(const stack\_t *ss, stack\_t *oss)} - -Installa un nuovo stack per i segnali. - - \bodydesc{La funzione restituisce zero in caso di successo e -1 per un - errore, nel qual caso \var{errno} assumerà i valori: - - \begin{errlist} - \item[\macro{ENOMEM}] La dimensione specificata per il nuovo stack è minore - di \macro{MINSIGSTKSZ}. - \item[\macro{EPERM}] Uno degli indirizzi non è valido. - \item[\macro{EFAULT}] Si è cercato di cambiare lo stack alternativo mentre - questo è attivo (cioè il processo è in esecuzione su di esso). - \item[\macro{EINVAL}] \param{ss} non è nullo e \var{ss\_flags} contiene un - valore diverso da zero che non è \macro{SS\_DISABLE}. - \end{errlist}} -\end{prototype} - - %%% Local Variables: %%% mode: latex