X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=edbc674a269a802be44392f4542287b56a155fbe;hp=edd354a26e321b065c95919387238df87f86803e;hb=ff76d56c6a2c280cbe4f153173488871d7b12336;hpb=6e257bf71f9acd5839dbae72de3dc9523cfb47c9 diff --git a/signal.tex b/signal.tex index edd354a..edbc674 100644 --- a/signal.tex +++ b/signal.tex @@ -1,6 +1,6 @@ %% signal.tex %% -%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -8,6 +8,7 @@ %% license is included in the section entitled "GNU Free Documentation %% License". %% + \chapter{I segnali} \label{cha:signals} @@ -116,7 +117,7 @@ verr 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 gestore non sono operazioni atomiche, e -sono sempre possibili delle \textit{race condition}\itindex{race~condition} +sono sempre possibili delle \itindex{race~condition} \textit{race condition} (sull'argomento vedi quanto detto in sez.~\ref{sec:proc_multi_prog}). Un altro problema è che in questa semantica non esiste un modo per bloccare i @@ -136,7 +137,7 @@ 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} (o \textit{pending}). In genere questa -procedura viene effettuata dallo scheduler \itindex{scheduler} quando, +procedura viene effettuata dallo \itindex{scheduler} scheduler quando, riprendendo l'esecuzione del processo in questione, verifica la presenza del segnale nella \struct{task\_struct} e mette in esecuzione il gestore. @@ -209,7 +210,7 @@ ignorarlo). Normalmente l'invio al processo che deve ricevere il segnale è immediato ed avviene non appena questo viene rimesso in esecuzione dallo -scheduler \itindex{scheduler} che esegue l'azione specificata. Questo a meno +\itindex{scheduler} scheduler che esegue l'azione specificata. Questo a meno che il segnale in questione non sia stato bloccato prima della notifica, nel qual caso l'invio non avviene ed il segnale resta \textsl{pendente} indefinitamente. Quando lo si sblocca il segnale \textsl{pendente} sarà subito @@ -244,8 +245,8 @@ Un programma pu sez.~\ref{sec:sig_sigaction}). Se si è installato un gestore sarà quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema farà si che mentre viene eseguito il gestore di un segnale, quest'ultimo venga -automaticamente bloccato (così si possono evitare \textit{race - condition}\itindex{race~condition}). +automaticamente bloccato (così si possono evitare \itindex{race~condition} +\textit{race condition}). Nel caso non sia stata specificata un'azione, viene utilizzata l'azione standard che (come vedremo in sez.~\ref{sec:sig_standard}) è propria di ciascun @@ -260,7 +261,7 @@ un eventuale messaggio di errore. I segnali che rappresentano errori del programma (divisione per zero o violazioni di accesso) hanno anche la caratteristica di scrivere un file di -\itindex{core~dump}\textit{core dump} che registra lo stato del processo (ed +\itindex{core~dump} \textit{core dump} che registra lo stato del processo (ed in particolare della memoria e dello \itindex{stack} stack) prima della terminazione. Questo può essere esaminato in seguito con un debugger per investigare sulla causa dell'errore. Lo stesso avviene se i suddetti segnali @@ -347,7 +348,7 @@ colonna standard sono stati indicati anche gli standard in cui ciascun segnale 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 -\itindex{core~dump}\textit{core dump}), che può essere usata da un debugger +\itindex{core~dump} \textit{core dump}), che può essere usata da un debugger per esaminare lo stato dello \itindex{stack} stack e delle variabili al momento della ricezione del segnale. @@ -418,7 +419,7 @@ tipologia, verr \label{sec:sig_prog_error} Questi segnali sono generati quando il sistema, o in certi casi direttamente -l'hardware (come per i \itindex{page~fault}\textit{page fault} non validi) +l'hardware (come per i \itindex{page~fault} \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 @@ -426,7 +427,7 @@ una operazione aritmetica proibita) e l'esecuzione non pu In genere si intercettano questi segnali per permettere al programma di terminare in maniera pulita, ad esempio per ripristinare le impostazioni della -console o eliminare i file di lock\index{file!di lock} prima dell'uscita. In +console o eliminare i \index{file!di lock} file di lock prima dell'uscita. In questo caso il gestore deve concludersi ripristinando l'azione predefinita e rialzando il segnale, in questo modo il programma si concluderà senza effetti spiacevoli, ma riportando lo stesso stato di uscita che avrebbe avuto se il @@ -434,7 +435,7 @@ gestore non ci fosse stato. L'azione predefinita per tutti questi segnali è causare la terminazione del processo che li ha causati. In genere oltre a questo il segnale provoca pure -la registrazione su disco di un file di \itindex{core~dump}\textit{core dump} +la registrazione su disco di un file di \itindex{core~dump} \textit{core dump} che viene scritto in un file \file{core} nella directory corrente del processo al momento dell'errore, che il debugger può usare per ricostruire lo stato del programma al momento della terminazione. Questi segnali sono: @@ -518,19 +519,19 @@ segnali sono: comando \cmd{kill} o dall'invio sul terminale del carattere di controllo INTR (interrupt, generato dalla sequenza \cmd{C-c}). -\item[\const{SIGQUIT}] È analogo a \const{SIGINT} con la differenza - che è controllato da un altro carattere di controllo, QUIT, - corrispondente alla sequenza \texttt{C-\bslash}. A differenza del - precedente l'azione predefinita, oltre alla terminazione del - processo, comporta anche la creazione di un - \itindex{core~dump}\textit{core dump}. +\item[\const{SIGQUIT}] È analogo a \const{SIGINT} con la differenza che è + controllato da un altro carattere di controllo, QUIT, corrispondente alla + sequenza \texttt{C-\bslash}. A differenza del precedente l'azione + predefinita, oltre alla terminazione del processo, comporta anche la + creazione di un \itindex{core~dump} \textit{core dump}. In genere lo si può pensare come corrispondente ad una condizione di errore del programma rilevata dall'utente. Per questo motivo non è opportuno fare eseguire al gestore di questo segnale le operazioni di pulizia normalmente previste (tipo la cancellazione di file temporanei), dato che in certi casi - esse possono eliminare informazioni utili nell'esame dei \textit{core dump}. - \itindex{core~dump} + esse possono eliminare informazioni utili nell'esame dei \itindex{core~dump} + \textit{core dump}. + \item[\const{SIGKILL}] Il nome è utilizzato per terminare in maniera immediata qualunque programma. Questo segnale non può essere né intercettato, né @@ -805,7 +806,7 @@ programmi eseguiti in background, che altrimenti sarebbero interrotti da una successiva pressione di \texttt{C-c} o \texttt{C-y}. Per quanto riguarda il comportamento di tutte le altre system call si danno -sostanzialmente due casi, a seconda che esse siano\index{system~call~lente} +sostanzialmente due casi, a seconda che esse siano \index{system~call~lente} \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 @@ -821,7 +822,7 @@ eseguito prima che la system call sia ritornata. Un elenco dei casi in cui si presenta questa situazione è il seguente: \begin{itemize*} \item la lettura da file che possono bloccarsi in attesa di dati non ancora - presenti (come per certi file di dispositivo\index{file!di~dispositivo}, i + presenti (come per certi \index{file!di~dispositivo} file di dispositivo, i socket o le pipe); \item la scrittura sugli stessi file, nel caso in cui dati non possano essere accettati immediatamente (di nuovo comune per i socket); @@ -1376,7 +1377,7 @@ Chiaramente, anche se il tempo pu nanosecondo, la precisione di \func{nanosleep} è determinata dalla risoluzione temporale del timer di sistema. Perciò la funzione attenderà comunque il tempo specificato, ma prima che il processo possa tornare ad essere eseguito -occorrerà almeno attendere il successivo giro di scheduler \itindex{scheduler} +occorrerà almeno attendere il successivo giro di \itindex{scheduler} scheduler e cioè un tempo che a seconda dei casi può arrivare fino a 1/\const{HZ}, (sempre che il sistema sia scarico ed il processa venga immediatamente rimesso in esecuzione); per questo motivo il valore restituito in \param{rem} è sempre @@ -1400,16 +1401,16 @@ conclusione di un processo padre.\footnote{in realtà in SVr4 eredita la semantica di System V, in cui il segnale si chiama \const{SIGCLD} e viene trattato in maniera speciale; in System V infatti se si imposta esplicitamente l'azione a \const{SIG\_IGN} il - segnale non viene generato ed il sistema non genera zombie\index{zombie} (lo - stato di terminazione viene scartato senza dover chiamare una \func{wait}). - L'azione predefinita è sempre quella di ignorare il segnale, ma non attiva - questo comportamento. Linux, come BSD e POSIX, non supporta questa semantica - ed usa il nome di \const{SIGCLD} come sinonimo di \const{SIGCHLD}.} In -generale dunque, quando non interessa elaborare lo stato di uscita di un -processo, si può completare la gestione della terminazione installando un -gestore per \const{SIGCHLD} il cui unico compito sia quello di chiamare -\func{waitpid} per completare la procedura di terminazione in modo da evitare -la formazione di zombie\index{zombie}. + segnale non viene generato ed il sistema non genera \index{zombie} zombie + (lo stato di terminazione viene scartato senza dover chiamare una + \func{wait}). L'azione predefinita è sempre quella di ignorare il segnale, + ma non attiva questo comportamento. Linux, come BSD e POSIX, non supporta + questa semantica ed usa il nome di \const{SIGCLD} come sinonimo di + \const{SIGCHLD}.} In generale dunque, quando non interessa elaborare lo +stato di uscita di un processo, si può completare la gestione della +terminazione installando un gestore per \const{SIGCHLD} il cui unico compito +sia quello di chiamare \func{waitpid} per completare la procedura di +terminazione in modo da evitare la formazione di \index{zombie} zombie. In fig.~\ref{fig:sig_sigchld_handl} è mostrato il codice contenente una implementazione generica di una funzione di gestione per \const{SIGCHLD}, (che @@ -1417,7 +1418,7 @@ si trova nei sorgenti allegati nel file \file{SigHand.c}); se ripetiamo i test di sez.~\ref{sec:proc_termination}, invocando \cmd{forktest} con l'opzione \cmd{-s} (che si limita ad effettuare l'installazione di questa funzione come gestore di \const{SIGCHLD}) potremo verificare che non si ha più la creazione -di zombie\index{zombie}. +di \index{zombie} zombie. \begin{figure}[!htb] \footnotesize \centering @@ -1457,7 +1458,7 @@ rimosso verr Allora, nel caso della terminazione dei processi figli, se si chiamasse \func{waitpid} una sola volta, essa leggerebbe lo stato di terminazione per un solo processo, anche se i processi terminati sono più di uno, e gli altri -resterebbero in stato di zombie\index{zombie} per un tempo indefinito. +resterebbero in stato di \index{zombie} zombie per un tempo indefinito. Per questo occorre ripetere la chiamata di \func{waitpid} fino a che essa non ritorni un valore nullo, segno che non resta nessun processo di cui si debba @@ -1473,9 +1474,9 @@ tutti gli stati di terminazione sono stati ricevuti. Le funzioni esaminate finora fanno riferimento alle modalità più elementari della gestione dei segnali; non si sono pertanto ancora prese in -considerazione le tematiche più complesse, collegate alle varie \textit{race - condition}\itindex{race~condition} che i segnali possono generare e alla -natura asincrona degli stessi. +considerazione le tematiche più complesse, collegate alle varie +\itindex{race~condition} \textit{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 @@ -1516,12 +1517,12 @@ l'interruzione di \func{pause} venisse causata da un altro segnale. 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 \textit{race condition}\itindex{race~condition}. +presenta una pericolosa \itindex{race~condition} \textit{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 di quest'ultima, cosicché essa sarebbe eseguita dopo l'arrivo di \const{SIGALRM}. In questo caso ci si -troverebbe di fronte ad un deadlock\itindex{deadlock}, in quanto \func{pause} +troverebbe di fronte ad un \itindex{deadlock} 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 @@ -1578,12 +1579,12 @@ quale potr segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}). Questo è il tipico esempio di caso, già citato in -sez.~\ref{sec:proc_race_cond}, in cui si genera una -\itindex{race~condition}\textit{race condition}; infatti, in una situazione in -cui un segnale è già arrivato (e \var{flag} è già ad 1) se un altro segnale -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. +sez.~\ref{sec:proc_race_cond}, in cui si genera una \itindex{race~condition} +\textit{race condition}; infatti, in una situazione in cui un segnale è già +arrivato (e \var{flag} è già ad 1) se un altro segnale 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 delle funzioni più sofisticate di quelle finora illustrate, queste hanno la @@ -1973,7 +1974,7 @@ 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 \textit{race condition}\itindex{race~condition} restano aperte +dei casi di \itindex{race~condition} \textit{race condition} restano aperte alcune possibilità legate all'uso di \func{pause}; il caso è simile a quello del problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e cioè la possibilità che il processo riceva il segnale che si intende usare per @@ -2032,12 +2033,11 @@ fine (\texttt{\small 22}), e al contempo si prepara la maschera dei segnali \var{sleep\_mask} per riattivare \const{SIGALRM} all'esecuzione di \func{sigsuspend}. -In questo modo non sono più possibili \textit{race - condition}\itindex{race~condition} dato che \const{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: +In questo modo non sono più possibili \itindex{race~condition} \textit{race + condition} dato che \const{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 con \func{sigprocmask}; @@ -2047,8 +2047,8 @@ i seguenti: \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\itindex{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione -di \func{sigsuspend}. +\itindex{deadlock} deadlock dovuto all'arrivo del segnale prima +dell'esecuzione di \func{sigsuspend}. \itindend{signal~mask} @@ -2200,7 +2200,7 @@ due comportamenti il programma deve assumere; i loro prototipi sono: \headdecl{setjmp.h} \funcdecl{int sigsetjmp(sigjmp\_buf env, int savesigs)} Salva il contesto - dello stack per un salto non-locale\index{salto~non-locale}. + dello stack per un \index{salto~non-locale} salto non-locale. \funcdecl{void siglongjmp(sigjmp\_buf env, int val)} Esegue un salto non-locale su un precedente contesto. @@ -2212,7 +2212,7 @@ due comportamenti il programma deve assumere; i loro prototipi sono: Le due funzioni prendono come primo argomento la variabile su cui viene salvato il contesto dello \itindex{stack} stack per permettere il -\index{salto~non-locale}salto non-locale; nel caso specifico essa è di tipo +\index{salto~non-locale} salto non-locale; nel caso specifico essa è di tipo \type{sigjmp\_buf}, e non \type{jmp\_buf} come per le analoghe di sez.~\ref{sec:proc_longjmp} in quanto in questo caso viene salvata anche la maschera dei segnali.