Altre funzioni di attesa, un po' meglio del while(1) ...
[gapil.git] / signal.tex
index 3bc1af18268fc02f28356d0a52e9988d0fd3d5f5..c2345f01e1c49dc0ba19659c9775ca2a2d6d81f6 100644 (file)
@@ -2,7 +2,7 @@
 \label{cha:signals}
 
 I segnali sono il primo e più semplice meccanismo di comunicazione nei
 \label{cha:signals}
 
 I segnali sono il primo e più semplice meccanismo di comunicazione nei
-confronti dei processi. Non portano con se nessuna informazione che non sia il
+confronti dei processi. Non portano con sé nessuna informazione che non sia il
 loro tipo; si tratta in sostanza di un'interruzione software portata ad un
 processo.
 
 loro tipo; si tratta in sostanza di un'interruzione software portata ad un
 processo.
 
@@ -15,7 +15,7 @@ esempio vengono usati per il controllo di sessione), per notificare eventi
 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à
 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 generazionem fino ad esaminare in dettaglio funzioni e le metodologie di
+di generazione fino ad esaminare in dettaglio funzioni e le metodologie di
 gestione.
 
 
 gestione.
 
 
@@ -243,7 +243,7 @@ non 
 \var{task\_struct} del processo; si dice così che il segnale diventa
 \textsl{pendente} (o \textit{pending}), e rimane tale fino al momento in cui
 verrà notificato al processo (o verrà specificata come azione di default
 \var{task\_struct} del processo; si dice così che il segnale diventa
 \textsl{pendente} (o \textit{pending}), e rimane tale fino al momento in cui
 verrà notificato al processo (o verrà specificata come azione di default
-quella di ingorarlo).
+quella di ignorarlo).
 
 Normalmente l'invio al processo che deve ricevere il segnale è immediato ed
 avviene non appena questo viene rimesso in esecuzione dallo scheduler che
 
 Normalmente l'invio al processo che deve ricevere il segnale è immediato ed
 avviene non appena questo viene rimesso in esecuzione dallo scheduler che
@@ -372,7 +372,7 @@ 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
 
 Per questo motivo ad ogni segnale viene associato un nome, definendo con una
 macro di preprocessore una costante uguale al suddetto numero. Sono questi
-nomi, che sono standardizzati e sostanzialemnte uniformi rispetto alle varie
+nomi, che sono standardizzati e sostanzialmente uniformi rispetto alle varie
 implementazioni, che si devono usare nei programmi. Tutti i nomi e le funzioni
 che concernono i segnali sono definiti nell'header di sistema \file{signal.h}.
 
 implementazioni, che si devono usare nei programmi. Tutti i nomi e le funzioni
 che concernono i segnali sono definiti nell'header di sistema \file{signal.h}.
 
@@ -819,20 +819,20 @@ 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
 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
-indenfinitamente, che per questo vengono chiamate \textsl{lente}. Un elenco
+indefinitamente, che per questo vengono chiamate \textsl{lente}. 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
   accettati immediatamente.
 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
   accettati immediatamente.
-\item apertura di un file di dipositivo che richiede operazioni non immediate
+\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
   eseguite immediatamente.
 \item le funzioni di intercomunicazione che si bloccano in attesa di risposte
   da altri processi.
   per una una risposta. 
 \item 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.
-\item la funzione \func{pause} (usata appunto per attendere l'arrivo di un
+\item la funzione \func{pause} (usata appunto per attendere l'-arrivo di un
   segnale).
 \item la funzione \func{wait} (se nessun processo figlio è ancora terminato).
 \end{itemize*}
   segnale).
 \item la funzione \func{wait} (se nessun processo figlio è ancora terminato).
 \end{itemize*}
@@ -945,7 +945,7 @@ un ciclo infinito.
 \label{sec:sig_kill_raise}
 
 Come accennato in \secref{sec:sig_types}, un segnale può essere generato
 \label{sec:sig_kill_raise}
 
 Come accennato in \secref{sec:sig_types}, un segnale può essere generato
-direttamente da un processo. L'invio di un sengale generico può essere
+direttamente da un processo. L'invio di un segnale generico può essere
 effettuato attraverso delle funzioni \func{kill} e \func{raise}. La prima
 serve per inviare un segnale al processo corrente, ed il suo prototipo è:
 \begin{prototype}{signal.h}{int raise(int sig)}
 effettuato attraverso delle funzioni \func{kill} e \func{raise}. La prima
 serve per inviare un segnale al processo corrente, ed il suo prototipo è:
 \begin{prototype}{signal.h}{int raise(int sig)}
@@ -1180,7 +1180,7 @@ Si deve comunque tenere presente che la precisione di queste funzioni 
 limitata da quella del timer di sistema (in genere 10~ms). Il sistema assicura
 comunque che il segnale non sarà mai generato prima della scadenza programmata
 (l'arrotondamento cioè è sempre effettuato per eccesso). Una seconda causa di
 limitata da quella del timer di sistema (in genere 10~ms). Il sistema assicura
 comunque che il segnale non sarà mai generato prima della scadenza programmata
 (l'arrotondamento cioè è sempre effettuato per eccesso). Una seconda causa di
-potenziali ritardi è che il segnale viene generato alla scandenza del timer,
+potenziali ritardi è che il segnale viene generato alla scadenza del timer,
 ma poi deve essere consegnato; se il processo è attivo (questo è sempre vero
 per \macro{ITIMER\_VIRT}) la consegna è immediata, altrimenti può esserci un
 ulteriore ritardo che può variare a seconda del carico del sistema.
 ma poi deve essere consegnato; se il processo è attivo (questo è sempre vero
 per \macro{ITIMER\_VIRT}) la consegna è immediata, altrimenti può esserci un
 ulteriore ritardo che può variare a seconda del carico del sistema.
@@ -1236,16 +1236,94 @@ segnale 
   Pone il processo in stato di sleep fino al ritorno di un manipolatore.
   
   \bodydesc{La funzione ritorna solo dopo che un segnale è stato ricevuto ed
   Pone il processo in stato di sleep fino al ritorno di un manipolatore.
   
   \bodydesc{La funzione ritorna solo dopo che un segnale è stato ricevuto ed
-  il relativo manipilatore è ritornato, nel qual caso restituisce -1 e setta
+  il relativo manipolatore è ritornato, nel qual caso restituisce -1 e setta
   \var{errno} a \macro{EINTR}.}
 \end{prototype}
 
   \var{errno} a \macro{EINTR}.}
 \end{prototype}
 
+La funzione segnala sempre una condizione di errore (il successo sarebbe
+quello di aspettare indefinitamente). In genere si usa questa funzione quando
+si vuole mettere un processo in attesa di un qualche evento specifico che non
+è sotto il suo diretto controllo (ad esempio la si può usare per far reagire
+il processo ad un segnale inviato da un altro processo).
+
+
+Se invece si vuole fare attendere un processo per un determinato intervallo di
+tempo lo standard POSIX.1 definisce la funzione \func{sleep}, il cui prototipo
+è:
+\begin{prototype}{unistd.h}{unsigned int sleep(unsigned int seconds)}
+  
+  Pone il processo in stato di sleep per \param{seconds} secondi.
+  
+  \bodydesc{La funzione restituisce zero se l'attesa viene completata, o il
+  numero di secondi restanti se viene interrotta da un segnale.}
+\end{prototype}
+
+La funzione attende per il tempo specificato, a meno di non essere interrotta
+da un segnale. In questo caso non è una buona idea ripetere la chiamata per il
+tempo rimanente, in quanto la riattivazione del processo può avvenire in un
+qualunque momento, ma il valore restituito sarà sempre arrotondato al secondo,
+con la conseguenza che, se la successione dei segnali è particolarmente
+sfortunata, si potranno avere ritardi anche di parecchi secondi. In genere la
+scelta più sicura è quella di stabilire un termine per l'attesa, e ricalcolare
+tutte le volte il numero di secondi da aspettare.
+
+In alcune implementazioni inoltre l'uso di \func{sleep} può avere conflitti
+con quello di \macro{SIGALRM}, dato che la funzione può essere realizzata
+attraverso \func{pause} e \func{alarm} (in maniera analoga all'esempio che
+vedremo fra poco). In tal caso mescolare chiamata di \func{alarm} e
+\func{sleep} o modificare l'azione di \macro{SIGALRM}, può causare risultati
+indefiniti. Nel caso delle \acr{glibc} è stata usata una implementazione
+completamente indipendente e questi problemi non ci sono.
+
+La granularità di \func{sleep} permette di specificare attese in secondi, per
+questo sia sotto BSD4.3 che in SUSv2 è stata definita la funzione
+\func{usleep} (dove la \texttt{u} è intesa come sostituzione di $\mu$); i due
+standard hanno delle definizioni diverse, ma le \acr{glibc}
+seguono\footnote{secondo la man page almeno dalla versione 2.2.2.} seguono
+quella di SUSv2 che prevede il seguente prototipo: 
+\begin{prototype}{unistd.h}{int usleep(unsigned long usec)}
+  
+  Pone il processo in stato di sleep per \param{usec} microsecondi.
+  
+  \bodydesc{La funzione restituisce zero se l'attesa viene completata, o -1 in
+    caso di errore, nel qual caso \var{errno} è settata a \macro{EINTR}.}
+
+\end{prototype}
+
+Anche questa funzione può presentare problemi nell'interazione con
+\func{alarm} e \macro{SIGALRM}, ed è pertanto deprecata in favore di
+\func{nanosleep}, definita dallo standard POSIX1.b, il cui prototipo è:
+\begin{prototype}{unistd.h}{int nanosleep(const struct timespec *req, struct
+    timespec *rem)}
+  
+  Pone il processo in stato di sleep per il tempo specificato da \param{req}.
+  
+  \bodydesc{La funzione restituisce zero se l'attesa viene completata, o -1 in
+    caso di errore, nel qual caso \var{errno} è settata a \macro{EINVAL} o
+    \macro{EINTR}.}
+\end{prototype}
 
 
 
 
 
 
-\subsection{Le semantiche di \macro{SIGCHLD}}
+
+
+\subsection{La gestione di \macro{SIGCHLD}}
 \label{sec:sig_sigchld}
 
 \label{sec:sig_sigchld}
 
+Un semplice esempio per illustrare il funzionamento di un manipolatore di
+segnale è quello della gestione di \macro{SIGCHLD}.  Abbiamo visto in
+\secref{sec:proc_termination} che una delle azioni eseguite dal kernel alla
+conclusione di un processo è quella di inviare questo segnale al
+padre;\footnote{in realtà in SRV4 eredita la semantica di System V, in cui il
+  segnale si chiama \macro{SIGCLD} e viene trattato in maniera speciale; se si
+  setta esplicitamente l'azione a \macro{SIG\_IGN} il segnale non viene
+  generato ed il sistema non genera zombie (lo stato di terminazione viene
+  scartato senza dover chiamare una wait), l'azione di default è 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 \macro{SIGCLD} come
+  sinonimo di \macro{SIGCHLD}.} è pertanto naturale completare qui la
+trattazione della terminazione dei processi illustrando le modalità per
+gestire questo segnale.
 
 
 
 
 
 
@@ -1253,6 +1331,12 @@ segnale 
 \label{sec:sig_control}
 
 
 \label{sec:sig_control}
 
 
+\subsection{Un esempio di problema}
+\label{sec:sig_example}
+
+Come accennato è possibile implementare \func{sleep} a partire da dall'uso di
+\func{pause} e \func{alarm};
+
 
 
 \subsection{Le funzioni \func{sigprocmask} e \func{sigpending}}
 
 
 \subsection{Le funzioni \func{sigprocmask} e \func{sigpending}}