X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=signal.tex;h=60514f5ef5d9be1fe6e64b848eca71e04df0fb02;hb=b26cbb461558b73852b680d524e8f91675998116;hp=a8de40a995f1df471b88706afb946a2d6b774a25;hpb=406973e35011347c3812c671511ce738378a525b;p=gapil.git diff --git a/signal.tex b/signal.tex index a8de40a..60514f5 100644 --- a/signal.tex +++ b/signal.tex @@ -1,6 +1,6 @@ %% signal.tex %% -%% Copyright (C) 2000-2004 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2005 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", @@ -115,8 +115,8 @@ 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 race condition\index{race condition} +segnale e la reinstallazione del suo gestore non sono operazioni atomiche, e +sono sempre possibili delle race condition\index{\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 +136,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\index{scheduler} quando, +procedura viene effettuata dallo scheduler\index{\textit{scheduler}} quando, riprendendo l'esecuzione del processo in questione, verifica la presenza del segnale nella \struct{task\_struct} e mette in esecuzione il gestore. @@ -208,9 +208,9 @@ ignorarlo). Normalmente l'invio al processo che deve ricevere il segnale è immediato ed avviene non appena questo viene rimesso in esecuzione dallo -scheduler\index{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} +scheduler\index{\textit{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 notificato. Si tenga presente però che i segnali \textsl{pendenti} non si accodano, alla generazione infatti il kernel marca un flag nella @@ -244,7 +244,7 @@ sez.~\ref{sec:sig_sigaction}). Se si 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 race -condition\index{race condition}). +condition\index{\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 @@ -433,16 +433,13 @@ processo che li ha causati. In genere oltre a questo il segnale provoca pure la registrazione su disco di un file di \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: +al momento della terminazione. Questi segnali sono: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\const{SIGFPE}] Riporta un errore aritmetico fatale. Benché il nome derivi da \textit{floating point exception} si applica a tutti gli errori - aritmetici compresa la divisione per zero e l'overflow. - - Se il gestore ritorna il comportamento del processo è indefinito, ed - ignorare questo segnale può condurre ad un ciclo infinito. + aritmetici compresa la divisione per zero e l'overflow. Se il gestore + ritorna il comportamento del processo è indefinito, ed ignorare questo + segnale può condurre ad un ciclo infinito. % Per questo segnale le cose sono complicate dal fatto che possono esserci % molte diverse eccezioni che \texttt{SIGFPE} non distingue, mentre lo @@ -578,9 +575,8 @@ sempre la necessit Questi segnali operano in congiunzione con le funzioni di I/O asincrono. Per questo occorre comunque usare \func{fcntl} per abilitare un file descriptor a -generare questi segnali. - -L'azione predefinita è di essere ignorati. Questi segnali sono: +generare questi segnali. L'azione predefinita è di essere ignorati. Questi +segnali sono: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\const{SIGIO}] Questo segnale viene inviato quando un file descriptor è pronto per eseguire dell'input/output. In molti sistemi solo i @@ -651,10 +647,8 @@ cui si trattano gli argomenti relativi. Questi segnali sono: Questi segnali sono usati per riportare al programma errori generati da operazioni da lui eseguite; non indicano errori del programma quanto errori che impediscono il completamento dell'esecuzione dovute all'interazione con il -resto del sistema. - -L'azione predefinita di questi segnali è di terminare il processo, questi -segnali sono: +resto del sistema. L'azione predefinita di questi segnali è di terminare il +processo, questi segnali sono: \begin{basedescript}{\desclabelwidth{2.0cm}} \item[\const{SIGPIPE}] Sta per \textit{Broken pipe}. Se si usano delle pipe, (o delle FIFO o dei socket) è necessario, prima che un processo inizi a @@ -663,9 +657,12 @@ segnali sono: terminato inavvertitamente alla scrittura sulla pipe il kernel genera questo segnale. Se il segnale è bloccato, intercettato o ignorato la chiamata che lo ha causato fallisce, restituendo l'errore \errcode{EPIPE}. -\item[\const{SIGLOST}] Sta per \textit{Resource lost}. Viene generato quando - c'è un advisory lock su un file NFS, ed il server riparte dimenticando la - situazione precedente. +\item[\const{SIGLOST}] Sta per \textit{Resource lost}. Tradizionalmente è il + segnale che generato quando si ha un advisory lock su un file su NFS che + viene perso perché il server NFS è stato riavviato. Il progetto GNU lo + utilizza per indicare ad un client il crollo inaspettato di un server. In + Linux è definito come sinonimo di \const{SIGIO}.\footnote{ed è segnalato + come BUG nella pagina di manuale.} \item[\const{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 sez.~\ref{sec:sys_resource_limit}. @@ -786,7 +783,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 @@ -802,12 +799,13 @@ 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 file di dispositivo\index{file!di~dispositivo}, i socket\index{socket} o le pipe). \item la scrittura sugli stessi file, nel caso in cui dati non possano essere - accettati immediatamente. + accettati immediatamente (di nuovo comune per i socket). \item l'apertura di un file di dispositivo che richiede operazioni non - immediate per una risposta. + immediate per una risposta (ad esempio l'apertura di un nastro che deve + essere riavvolto). \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 @@ -817,12 +815,12 @@ presenta questa situazione \item la funzione \func{wait} (se nessun processo figlio è ancora terminato). \end{itemize*} -In questo caso si pone il problema di cosa fare una volta che il gestore -sia ritornato. La scelta originaria dei primi Unix era quella di far ritornare +In questo caso si pone il problema di cosa fare una volta che il gestore sia +ritornato. La scelta originaria dei primi Unix era quella di far ritornare anche la system call restituendo l'errore di \errcode{EINTR}. Questa è a tutt'oggi una scelta corrente, ma comporta che i programmi che usano dei -gestori controllino lo stato di uscita delle funzioni per ripeterne la -chiamata qualora l'errore fosse questo. +gestori controllino lo stato di uscita delle funzioni che eseguono una system +call lenta per ripeterne la chiamata qualora l'errore fosse questo. Dimenticarsi di richiamare una system call interrotta da un segnale è un errore comune, tanto che le \acr{glibc} provvedono una macro @@ -848,13 +846,13 @@ ritornano sempre indicando i byte trasferiti. \label{sec:sig_signal} L'interfaccia più semplice per la gestione dei segnali è costituita dalla -funzione \funcd{signal} che è definita fin dallo standard ANSI C. Quest'ultimo -però non considera sistemi multitasking, per cui la definizione è tanto vaga -da essere del tutto inutile in un sistema Unix; è questo il motivo per cui -ogni implementazione successiva ne ha modificato e ridefinito il +funzione \funcd{signal} che è definita fin dallo standard ANSI C. +Quest'ultimo però non considera sistemi multitasking, per cui la definizione è +tanto vaga da essere del tutto inutile in un sistema Unix; è questo il motivo +per cui ogni implementazione successiva ne ha modificato e ridefinito il comportamento, pur mantenendone immutato il prototipo\footnote{in realtà in alcune vecchie implementazioni (SVr4 e 4.3+BSD in particolare) vengono usati - alcuni parametri aggiuntivi per definire il comportamento della funzione, + alcuni argomenti aggiuntivi per definire il comportamento della funzione, vedremo in sez.~\ref{sec:sig_sigaction} che questo è possibile usando la funzione \func{sigaction}.} che è: \begin{prototype}{signal.h} @@ -1214,7 +1212,7 @@ valore corrente di un timer senza modificarlo, \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore e restituisce gli stessi errori di \func{getitimer}} \end{prototype} -\noindent i cui parametri hanno lo stesso significato e formato di quelli di +\noindent i cui argomenti hanno lo stesso significato e formato di quelli di \func{setitimer}. @@ -1341,7 +1339,7 @@ POSIX1.b, il cui prototipo Lo standard richiede che la funzione sia implementata in maniera del tutto indipendente da \func{alarm}\footnote{nel caso di Linux questo è fatto utilizzando direttamente il timer del kernel.} e sia utilizzabile senza -interferenze con l'uso di \const{SIGALRM}. La funzione prende come parametri +interferenze con l'uso di \const{SIGALRM}. La funzione prende come argomenti delle strutture di tipo \struct{timespec}, la cui definizione è riportata in fig.~\ref{fig:sys_timeval_struct}, che permettono di specificare un tempo con una precisione (teorica) fino al nanosecondo. @@ -1355,11 +1353,12 @@ 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\index{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 -arrotondato al multiplo successivo di 1/\const{HZ}. +occorrerà almeno attendere il successivo giro di +scheduler\index{\textit{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 arrotondato al multiplo successivo +di 1/\const{HZ}. In realtà è possibile ottenere anche pause più precise del centesimo di secondo usando politiche di scheduling real time come \const{SCHED\_FIFO} o @@ -1459,8 +1458,8 @@ 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\index{race condition} che i segnali possono generare e alla natura -asincrona degli stessi. +condition\index{\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 @@ -1501,13 +1500,14 @@ 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 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 \const{SIGALRM}. In questo caso ci si troverebbe di fronte ad un -deadlock\index{deadlock}, in quanto \func{pause} non verrebbe mai più -interrotta (se non in caso di un altro segnale). +presenta una pericolosa race condition\index{\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 quest'ultima, cosicché essa +sarebbe eseguita dopo l'arrivo di \const{SIGALRM}. In questo caso ci si +troverebbe di fronte ad un deadlock\index{\textit{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 sez.~\ref{sec:proc_longjmp}) per @@ -1563,10 +1563,10 @@ 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 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. +sez.~\ref{sec:proc_race_cond}, in cui si genera una race condition +\index{\textit{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 @@ -1579,6 +1579,7 @@ reagire alla ricezione di un segnale. \subsection{Gli \textsl{insiemi di segnali} o \textit{signal set}} \label{sec:sig_sigset} +\index{\textit{signal~set}|(} Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali originarie, nate con la semantica inaffidabile, hanno dei limiti non superabili; in particolare non è prevista nessuna funzione che permetta di @@ -1641,6 +1642,8 @@ ottenuto con \func{sigemptyset} o togliendo quelli che non servono da un insieme completo ottenuto con \func{sigfillset}. Infine \func{sigismember} permette di verificare la presenza di uno specifico segnale in un insieme. +\index{\textit{signal~set}|)} + \subsection{La funzione \func{sigaction}} @@ -1743,7 +1746,7 @@ in tab.~\ref{tab:sig_sa_flag}. \const{SA\_RESTART} & Riavvia automaticamente le \textit{slow system call} quando vengono interrotte dal suddetto segnale; riproduce cioè il comportamento standard - di BSD.\index{system call lente}\\ + di BSD.\index{system~call~lente}\\ \const{SA\_NOMASK} & Evita che il segnale corrente sia bloccato durante l'esecuzione del gestore.\\ \const{SA\_NODEFER} & Sinonimo di \const{SA\_NOMASK}.\\ @@ -1759,21 +1762,21 @@ in tab.~\ref{tab:sig_sa_flag}. \label{tab:sig_sa_flag} \end{table} -Come si può notare in fig.~\ref{fig:sig_sigaction} \func{sigaction} -permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ed è - stata aggiunta nei kernel della serie 2.1.x con l'introduzione dei segnali - real-time (vedi sez.~\ref{sec:sig_real_time}). In precedenza era possibile - ottenere alcune informazioni addizionali usando \var{sa\_handler} con un - secondo parametro addizionale di tipo \var{sigcontext}, che adesso è - deprecato.} di utilizzare due forme diverse di gestore, da specificare, a -seconda dell'uso o meno del flag \const{SA\_SIGINFO}, rispettivamente -attraverso i campi \var{sa\_sigaction} o \var{sa\_handler},\footnote{i due - tipi devono essere usati in maniera alternativa, in certe implementazioni - questi campi vengono addirittura definiti come \ctyp{union}.} Quest'ultima -è quella classica usata anche con \func{signal}, mentre la prima permette di -usare un gestore più complesso, in grado di ricevere informazioni più -dettagliate dal sistema, attraverso la struttura \struct{siginfo\_t}, -riportata in fig.~\ref{fig:sig_siginfo_t}. +Come si può notare in fig.~\ref{fig:sig_sigaction} \func{sigaction} permette +di utilizzare due forme diverse di gestore,\footnote{La possibilità è prevista + dallo standard POSIX.1b, ed è stata aggiunta nei kernel della serie 2.1.x + con l'introduzione dei segnali real-time (vedi + sez.~\ref{sec:sig_real_time}); in precedenza era possibile ottenere alcune + informazioni addizionali usando \var{sa\_handler} con un secondo parametro + addizionale di tipo \var{sigcontext}, che adesso è deprecato.} da +specificare, a seconda dell'uso o meno del flag \const{SA\_SIGINFO}, +rispettivamente attraverso i campi \var{sa\_sigaction} o +\var{sa\_handler},\footnote{i due tipi devono essere usati in maniera + alternativa, in certe implementazioni questi campi vengono addirittura + definiti come \ctyp{union}.} Quest'ultima è quella classica usata anche con +\func{signal}, mentre la prima permette di usare un gestore più complesso, in +grado di ricevere informazioni più dettagliate dal sistema, attraverso la +struttura \struct{siginfo\_t}, riportata in fig.~\ref{fig:sig_siginfo_t}. \begin{figure}[!htb] \footnotesize \centering @@ -1874,6 +1877,7 @@ estremamente semplice, \textit{signal mask}} \label{sec:sig_sigmask} +\index{\textit{signal mask}|(} Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like permettono si bloccare temporaneamente (o di eliminare completamente, impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un @@ -1951,10 +1955,10 @@ 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\index{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 +dei casi di race condition\index{\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 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 @@ -2010,11 +2014,12 @@ fine (\texttt{\small 27}), 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 race condition\index{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 race +condition\index{\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}. @@ -2024,8 +2029,9 @@ segnale, i passi sono sempre 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\index{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione -di \func{sigsuspend}. +deadlock\index{\textit{deadlock}} dovuto all'arrivo del segnale prima +dell'esecuzione di \func{sigsuspend}. +\index{\textit{signal mask}|)} \subsection{Ulteriori funzioni di gestione} @@ -2174,7 +2180,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 salto non-locale\index{salto~non-locale}. \funcdecl{void siglongjmp(sigjmp\_buf env, int val)} Esegue un salto non-locale su un precedente contesto. @@ -2186,7 +2192,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 stack per permettere il salto non-locale -\index{salto non-locale}; nel caso specifico essa è di tipo +\index{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. @@ -2335,7 +2341,7 @@ installato un gestore con \const{SA\_SIGINFO} e ci sono risorse disponibili, (vale a dire che c'è posto\footnote{la profondità della coda è indicata dalla costante \const{SIGQUEUE\_MAX}, una della tante costanti di sistema definite dallo standard POSIX che non abbiamo riportato esplicitamente in - sez.~\ref{sec:sys_limits}. Il suo valore minimo secondo lo standard, + sez.~\ref{sec:sys_limits}; il suo valore minimo secondo lo standard, \const{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32. Nel caso di Linux questo è uno dei parametri del kernel impostabili sia con \func{sysctl}, che scrivendolo direttamente in \file{/proc/sys/kernel/rtsig-max}, il valore predefinito è