X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=0c11317cdd11ffe81b69a6fec60c657b2e9f2581;hp=182de6abc4678a16eaa0c71b3fcf313c91f928d8;hb=b38fb9f5c8fb8360f7ac296baa8f4a0bdd692d1c;hpb=428bc5cd4e05a99bbcb57be6946eb4b1fa9dfca9 diff --git a/signal.tex b/signal.tex index 182de6a..0c11317 100644 --- a/signal.tex +++ b/signal.tex @@ -116,7 +116,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 race condition\index{\textit{race~condition}} +sono sempre possibili delle \textit{race condition}\itindex{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{\textit{scheduler}} quando, +procedura viene effettuata dallo scheduler\itindex{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,9 +209,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{\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} +scheduler\itindex{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 @@ -241,11 +241,11 @@ una delle tre possibilit Un programma può specificare queste scelte usando le due funzioni \func{signal} e \func{sigaction} (vedi sez.~\ref{sec:sig_signal} e -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 race -condition\index{\textit{race~condition}}). +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}). 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 @@ -279,7 +279,7 @@ di identificarli, e le funzioni che ne stampano la descrizione. Ciascun segnale è identificato rispetto al sistema da un numero, ma l'uso diretto di questo numero da parte dei programmi è da evitare, in quanto esso -può variare a seconda dell'implementazione del sistema, e nel caso si Linux, +può variare a seconda dell'implementazione del sistema, e nel caso di Linux, anche a seconda dell'architettura hardware. Per questo motivo ad ogni segnale viene associato un nome, definendo con una macro di preprocessore una costante uguale al suddetto numero. Sono questi @@ -415,11 +415,11 @@ tipologia, verr \label{sec:sig_prog_error} Questi segnali sono generati quando il sistema, o in certi casi direttamente -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. +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 +una operazione aritmetica proibita) e l'esecuzione non può essere proseguita. In genere si intercettano questi segnali per permettere al programma di terminare in maniera pulita, ad esempio per ripristinare le impostazioni della @@ -512,8 +512,8 @@ segnali sono: interruzione per il programma. È quello che viene generato di default dal 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 differenze che è - controllato da un'altro carattere di controllo, QUIT, corrispondente alla +\item[\const{SIGQUIT}] È analogo a \const{SIGINT} con la differenza che è + controllato da un altro carattere di controllo, QUIT, corrispondente alla sequenza \verb|C-\|. A differenza del precedente l'azione predefinita, oltre alla terminazione del processo, comporta anche la creazione di un core dump. @@ -890,9 +890,9 @@ Il numero di segnale passato in \param{signum} pu direttamente con una delle costanti definite in sez.~\ref{sec:sig_standard}. Il gestore \param{handler} invece, oltre all'indirizzo della funzione da chiamare all'occorrenza del segnale, può assumere anche i due valori costanti -\const{SIG\_IGN} con cui si dice ignorare il segnale e \const{SIG\_DFL} per +\const{SIG\_IGN} con cui si dice di ignorare il segnale e \const{SIG\_DFL} per reinstallare l'azione predefinita.\footnote{si ricordi però che i due segnali - \const{SIGKILL} e \const{SIGSTOP} non possono essere ignorati né + \const{SIGKILL} e \const{SIGSTOP} non possono essere né ignorati né intercettati; l'uso di \const{SIG\_IGN} per questi segnali non ha alcun effetto.} @@ -1076,10 +1076,9 @@ segnale; siccome alla chiamata viene cancellato ogni precedente allarme, questo può essere usato per cancellare una programmazione precedente. La funzione inoltre ritorna il numero di secondi rimanenti all'invio -dell'allarme precedentemente programmato, in modo che sia possibile -controllare se non si cancella un precedente allarme ed eventualmente -predisporre le opportune misure per gestire il caso di necessità di più -interruzioni. +dell'allarme programmato in precedenza. In questo modo è possibile controllare +se non si è cancellato un precedente allarme e predisporre eventuali misure +che permettano di gestire il caso in cui servono più interruzioni. In sez.~\ref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono associati tre tempi diversi: il \textit{clock time}, l'\textit{user time} ed @@ -1113,7 +1112,7 @@ suo prototipo itimerval *value, struct itimerval *ovalue)} Predispone l'invio di un segnale di allarme alla scadenza dell'intervallo - \param{value} sul timer specificato da \func{which}. + \param{value} sul timer specificato da \param{which}. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore, nel qual caso \var{errno} assumerà uno dei valori \errval{EINVAL} o @@ -1209,7 +1208,7 @@ valore corrente di un timer senza modificarlo, \begin{prototype}{sys/time.h}{int getitimer(int which, struct itimerval *value)} - Legge in \param{value} il valore del timer specificato da \func{which}. + Legge in \param{value} il valore del timer specificato da \param{which}. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore e restituisce gli stessi errori di \func{getitimer}} @@ -1241,7 +1240,7 @@ il processo non viene terminato direttamente dal gestore sia la stessa \func{abort} a farlo al ritorno dello stesso. Inoltre, sempre seguendo lo standard POSIX, prima della terminazione tutti i file aperti e gli stream saranno chiusi ed i buffer scaricati su disco. Non verranno invece eseguite le -eventuali funzioni registrate con \func{at\_exit} e \func{on\_exit}. +eventuali funzioni registrate con \func{atexit} e \func{on\_exit}. \subsection{Le funzioni di pausa e attesa} @@ -1355,12 +1354,11 @@ 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{\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}. +occorrerà almeno attendere il successivo giro di scheduler\itindex{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 @@ -1398,12 +1396,6 @@ di sez.~\ref{sec:proc_termination}, invocando \cmd{forktest} con l'opzione gestore di \const{SIGCHLD}) potremo verificare che non si ha più la creazione di zombie\index{zombie}. -% è pertanto -% naturale usare un esempio che ci permette di concludere la trattazione della -% terminazione dei processi. -% In questo caso si è tratterà di illustrare un esempio relativo ad un -% gestore per che è previsto ritornare, - \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} @@ -1411,7 +1403,7 @@ di zombie\index{zombie}. \end{minipage} \normalsize \caption{Codice di una funzione generica di gestione per il segnale - \texttt{SIGCHLD}.} + \texttt{SIGCHLD}.} \label{fig:sig_sigchld_handl} \end{figure} @@ -1421,7 +1413,7 @@ comincia (\texttt{\small 6--7}) con il salvare lo stato corrente di \var{errno}, in modo da poterlo ripristinare prima del ritorno del gestore (\texttt{\small 16--17}). In questo modo si preserva il valore della variabile visto dal corso di esecuzione principale del processo, che altrimenti sarebbe -sovrascritto dal valore restituito nella successiva chiamata di \func{wait}. +sovrascritto dal valore restituito nella successiva chiamata di \func{waitpid}. Il compito principale del gestore è quello di ricevere lo stato di terminazione del processo, cosa che viene eseguita nel ciclo in @@ -1437,7 +1429,7 @@ Questo pu che molti processi figli terminino in rapida successione. Esso inoltre si presenta tutte le volte che un segnale viene bloccato: per quanti siano i segnali emessi durante il periodo di blocco, una volta che quest'ultimo sarà -rimosso sarà recapitato un solo segnale. +rimosso verrà recapitato un solo segnale. Allora, nel caso della terminazione dei processi figli, se si chiamasse \func{waitpid} una sola volta, essa leggerebbe lo stato di terminazione per un @@ -1458,8 +1450,8 @@ 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 race -condition\index{\textit{race~condition}} che i segnali possono generare e alla +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. Affronteremo queste problematiche in questa sezione, partendo da un esempio @@ -1501,14 +1493,13 @@ 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{\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 +presenta una pericolosa \textit{race condition}\itindex{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\index{\textit{deadlock}}, in quanto -\func{pause} non verrebbe mai più interrotta (se non in caso di un altro -segnale). +troverebbe di fronte ad un deadlock\itindex{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 @@ -1565,10 +1556,11 @@ 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 -\index{\textit{race~condition}}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. +\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 funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla @@ -1581,7 +1573,8 @@ reagire alla ricezione di un segnale. \subsection{Gli \textsl{insiemi di segnali} o \textit{signal set}} \label{sec:sig_sigset} -\index{\textit{signal~set}|(} +\itindbeg{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 @@ -1643,8 +1636,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}|)} +\itindend{signal~set} \subsection{La funzione \func{sigaction}} @@ -1845,7 +1838,7 @@ sempre il caso di evitare l'uso di \func{signal} a favore di \func{sigaction}. \includecodesample{listati/Signal.c} \end{minipage} \normalsize - \caption{La funzione \funcd{Signal}, equivalente a \func{signal}, definita + \caption{La funzione \func{Signal}, equivalente a \func{signal}, definita attraverso \func{sigaction}.} \label{fig:sig_Signal_code} \end{figure} @@ -1877,9 +1870,9 @@ estremamente semplice, \textit{signal mask}} \label{sec:sig_sigmask} -\index{\textit{signal mask}|(} +\itindbeg{signal~mask} Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like -permettono si bloccare temporaneamente (o di eliminare completamente, +permettono di bloccare temporaneamente (o di eliminare completamente, impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un processo. Questo è fatto specificando la cosiddetta \textsl{maschera dei segnali} (o \textit{signal mask}) del processo\footnote{nel caso di Linux @@ -1894,7 +1887,7 @@ Uno dei problemi evidenziatisi con l'esempio di fig.~\ref{fig:sig_event_wrong} è che in molti casi è necessario proteggere delle sezioni di codice (nel caso in questione la sezione fra il controllo e la eventuale cancellazione del flag che testimoniava l'avvenuta occorrenza del segnale) in modo da essere sicuri -che essi siano eseguiti senza interruzioni. +che essi siano eseguite senza interruzioni. Le operazioni più semplici, come l'assegnazione o il controllo di una variabile (per essere sicuri si può usare il tipo \type{sig\_atomic\_t}) di @@ -1955,7 +1948,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 race condition\index{\textit{race~condition}} restano aperte +dei casi di \textit{race condition}\itindex{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 @@ -2014,8 +2007,8 @@ 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 race -condition\index{\textit{race~condition}} dato che \const{SIGALRM} viene +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 @@ -2029,9 +2022,10 @@ 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{\textit{deadlock}} dovuto all'arrivo del segnale prima -dell'esecuzione di \func{sigsuspend}. -\index{\textit{signal mask}|)} +deadlock\itindex{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione +di \func{sigsuspend}. + +\itindend{signal~mask} \subsection{Ulteriori funzioni di gestione} @@ -2145,7 +2139,7 @@ sullo stack alternativo (nel qual caso non In genere si installa uno stack alternativo per i segnali quando si teme di avere problemi di esaurimento dello stack standard o di superamento di un -limite imposto con chiamata de tipo \code{setrlimit(RLIMIT\_STACK, \&rlim)}. +limite imposto con chiamate del tipo \code{setrlimit(RLIMIT\_STACK, \&rlim)}. In tal caso infatti si avrebbe un segnale di \const{SIGSEGV}, che potrebbe essere gestito soltanto avendo abilitato uno stack alternativo. @@ -2333,7 +2327,7 @@ funzione, \funcd{sigqueue}, il cui prototipo Il comportamento della funzione è analogo a quello di \func{kill}, ed i privilegi occorrenti ad inviare il segnale ad un determinato processo sono gli -stessi; un valore nullo di \func{signo} permette di verificare le condizioni +stessi; un valore nullo di \param{signo} permette di verificare le condizioni di errore senza inviare nessun segnale. Se il segnale è bloccato la funzione ritorna immediatamente, se si è